Compare commits

..

31 Commits

Author SHA1 Message Date
Peter Dimov
2aa5d4d97f Add definitions of ::in_place_* for result specializations. Fixes #115. 2023-12-15 03:17:21 +02:00
Peter Dimov
18edbf75d0 Test ::in_place_* for result specializations. Refs #115. 2023-12-15 02:44:14 +02:00
Peter Dimov
52220a0351 Add definitions of result<T, E>::in_place_*. Refs #115. 2023-12-15 02:24:18 +02:00
Peter Dimov
ffa67ab005 Add test for ODR-use of ::in_place_* (refs #115) 2023-12-15 02:11:19 +02:00
Peter Dimov
d8399efcac Update ci.yml 2023-12-15 01:42:22 +02:00
Peter Dimov
8bc32b7267 Update documentation 2023-10-31 04:20:33 +02:00
Peter Dimov
d11dd4b396 Add operator&=( result&, unary-returning-result ) 2023-10-31 03:08:02 +02:00
Peter Dimov
ca5bca39ce Add operator&=( result&, unary-returning-value ) 2023-10-31 02:44:45 +02:00
Peter Dimov
a58115cb50 Reorder operator& code for better codegen 2023-10-31 01:51:38 +02:00
Peter Dimov
1bc08296de Update documentation 2023-10-30 21:03:39 +02:00
Peter Dimov
25479216b3 Fix test file names 2023-10-30 00:52:38 +02:00
Peter Dimov
54d3b253b1 Add operator&( result, unary-returning-result ) 2023-10-29 20:57:29 +02:00
Peter Dimov
194b84e663 Add operator&( result, unary-returning-value ) 2023-10-29 19:37:43 +02:00
Peter Dimov
47a08cb35b Update documentation 2023-10-29 19:14:13 +02:00
Peter Dimov
7ffd63d54c Fix rvalue result<void> cases 2023-10-29 19:13:11 +02:00
Peter Dimov
92c24da9a1 Document operator| 2023-10-29 03:10:27 +02:00
Peter Dimov
dc73ca428b Add operator|( result, nullary-returning-result ) 2023-10-29 03:20:08 +03:00
Peter Dimov
c1fa3619b6 Add operator|( result, nullary-returning-value ) 2023-10-29 02:32:19 +03:00
Peter Dimov
0cd351014b Remove C++14-ism 2023-10-29 01:41:50 +03:00
Peter Dimov
d38e54d4c3 Add operator|( result, value ) 2023-10-29 01:30:01 +03:00
Peter Dimov
fa3331412d Update ci.yml 2023-10-28 20:53:44 +03:00
Peter Dimov
b899c49ae8 Update .drone.jsonnet 2023-10-21 04:17:30 +03:00
Peter Dimov
61a0e244da Add some more test cases exercising result initialization from {} 2023-10-20 21:49:20 +03:00
Peter Dimov
eb788615de Update ci.yml 2023-10-20 03:04:29 +03:00
Peter Dimov
84fd43e14a Update C++03 deprecation message 2023-10-19 18:15:05 +03:00
Peter Dimov
b0ef682e3d Update documentation 2023-09-14 02:20:46 +03:00
Peter Dimov
c360ff1b1c Add a converting constructor to result<void> 2023-09-12 04:48:45 +03:00
Peter Dimov
951b3fe7b4 Add result<U&, E> specialization. Fixes #72. 2023-09-12 03:34:24 +03:00
Peter Dimov
a57c568324 Do not use <shared_mutex> when BOOST_USE_WINAPI_VERSION is 0x5xx (Windows XP). Fixes #113. 2023-09-04 16:28:34 +03:00
Peter Dimov
4843453528 Update ci.yml 2023-09-04 13:04:34 +03:00
Peter Dimov
2e7e46a802 Update C++03 deprecation message 2023-06-03 02:31:27 +03:00
40 changed files with 4405 additions and 18 deletions

View File

@@ -226,6 +226,20 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
"g++-12-multilib",
),
linux_pipeline(
"Linux 23.04 GCC 13 32",
"cppalliance/droneubuntu2304:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '03,11,14,17,20,2b', ADDRMD: '32' },
"g++-13-multilib",
),
linux_pipeline(
"Linux 23.04 GCC 13 64",
"cppalliance/droneubuntu2304:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '03,11,14,17,20,2b', ADDRMD: '64' },
"g++-13-multilib",
),
linux_pipeline(
"Linux 16.04 Clang 3.5",
"cppalliance/droneubuntu1604:1",
@@ -283,6 +297,13 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
["deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main"],
),
linux_pipeline(
"Linux 23.04 Clang 16",
"cppalliance/droneubuntu2304:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-16', CXXSTD: '11,14,17,20,2b' },
"clang-16",
),
macos_pipeline(
"MacOS 10.15 Xcode 12.2 UBSAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,1z' } + ubsan,
@@ -293,6 +314,18 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,1z' } + asan,
),
macos_pipeline(
"MacOS 12.4 Xcode 13.4.1 UBSAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11,14,17,20,2b' } + ubsan,
xcode_version = "13.4.1", osx_version = "monterey", arch = "arm64",
),
macos_pipeline(
"MacOS 12.4 Xcode 13.4.1 ASAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11,14,17,20,2b' } + asan,
xcode_version = "13.4.1", osx_version = "monterey", arch = "arm64",
),
windows_pipeline(
"Windows VS2015 msvc-14.0",
"cppalliance/dronevs2015",

View File

@@ -5,6 +5,7 @@
# https://www.boost.org/LICENSE_1_0.txt
set -ex
export PATH=~/.local/bin:/usr/local/bin:$PATH
DRONE_BUILD_DIR=$(pwd)

View File

@@ -55,6 +55,11 @@ jobs:
cxxstd: "03,11,14,17,20,2b"
os: ubuntu-22.04
install: g++-12
- toolset: gcc-13
cxxstd: "03,11,14,17,20,2b"
os: ubuntu-latest
container: ubuntu:23.04
install: g++-13
- toolset: clang
compiler: clang++-3.9
cxxstd: "03,11,14"
@@ -108,24 +113,42 @@ jobs:
- toolset: clang
compiler: clang++-13
cxxstd: "03,11,14,17,20,2b"
os: ubuntu-22.04
container: ubuntu:22.04
os: ubuntu-latest
install: clang-13
- toolset: clang
compiler: clang++-14
cxxstd: "03,11,14,17,20,2b"
os: ubuntu-22.04
container: ubuntu:22.04
os: ubuntu-latest
install: clang-14
- toolset: clang
compiler: clang++-15
cxxstd: "03,11,14,17,20,2b"
os: ubuntu-22.04
container: ubuntu:22.04
os: ubuntu-latest
install: clang-15
- toolset: clang
compiler: clang++-16
cxxstd: "03,11,14,17,20,2b"
container: ubuntu:23.04
os: ubuntu-latest
install: clang-16
- toolset: clang
compiler: clang++-17
cxxstd: "03,11,14,17,20,2b"
container: ubuntu:23.10
os: ubuntu-latest
install: clang-17
- toolset: clang
cxxstd: "03,11,14,17,2a"
os: macos-11
- toolset: clang
cxxstd: "03,11,14,17,2a"
cxxstd: "03,11,14,17,20,2b"
os: macos-12
- toolset: clang
cxxstd: "03,11,14,17,20,2b"
os: macos-13
runs-on: ${{matrix.os}}
container: ${{matrix.container}}
@@ -141,11 +164,13 @@ jobs:
if: matrix.container
run: |
apt-get update
apt-get -y install sudo python git g++
apt-get -y install sudo python3 git g++
- name: Install packages
if: matrix.install
run: sudo apt-get -y install ${{matrix.install}}
run: |
sudo apt-get update
sudo apt-get -y install ${{matrix.install}}
- name: Setup Boost
run: |
@@ -165,7 +190,7 @@ jobs:
cd boost-root
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
python3 tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
./bootstrap.sh
./b2 -d0 headers
@@ -197,7 +222,7 @@ jobs:
addrmd: 32,64
os: windows-2022
- toolset: clang-win
cxxstd: "14,17,latest"
cxxstd: "14,17,20,latest"
addrmd: 32,64
os: windows-2022
- toolset: gcc
@@ -247,6 +272,7 @@ jobs:
- os: ubuntu-22.04
- os: macos-11
- os: macos-12
- os: macos-13
runs-on: ${{matrix.os}}
@@ -294,6 +320,7 @@ jobs:
- os: ubuntu-22.04
- os: macos-11
- os: macos-12
- os: macos-13
runs-on: ${{matrix.os}}
@@ -351,6 +378,7 @@ jobs:
- os: ubuntu-22.04
- os: macos-11
- os: macos-12
- os: macos-13
runs-on: ${{matrix.os}}

View File

@@ -8,6 +8,13 @@ https://www.boost.org/LICENSE_1_0.txt
# Revision History
:idprefix:
## Changes in Boost 1.84
* Added support for `result<U&, E>`.
* Added `operator|` for `result`.
* Added `operator&` for `result`.
* Added `operator&=` for `result`.
## Changes in Boost 1.81
* The macro `BOOST_SYSTEM_DISABLE_THREADS` can now be defined to disable

View File

@@ -1517,6 +1517,38 @@ constexpr in_place_error_t in_place_error{};
template<class T, class E = error_code> class result;
template<class E> class result<void, E>;
template<class U, class E> class result<U&, E>;
// operator|
template<class T, class E, class U> T operator|( result<T, E> const& r, U&& u );
template<class T, class E, class U> T operator|( result<T, E>&& r, U&& u );
template<class T, class E, class F> T operator|( result<T, E> const& r, F&& f );
template<class T, class E, class F> T operator|( result<T, E>&& r, F&& f );
template<class T, class E, class F, class R = ...> R operator|( result<T, E> const& r, F&& f );
template<class T, class E, class F, class R = ...> R operator|( result<T, E>&& r, F&& f );
template<class E, class F, class R = ...> R operator|( result<void, E> const& r, F&& f );
template<class E, class F, class R = ...> R operator|( result<void, E>&& r, F&& f );
// operator&
template<class T, class E, class F, class U = ...>
result<U, E> operator&( result<T, E> const& r, F&& f );
template<class T, class E, class F, class U = ...>
result<U, E> operator&( result<T, E>&& r, F&& f );
template<class T, class E, class F, class R = ...> R operator&( result<T, E> const& r, F&& f );
template<class T, class E, class F, class R = ...> R operator&( result<T, E>&& r, F&& f );
// operator&=
template<class T, class E, class F, class U = ...>
result<T, E>& operator&=( result<T, E>& r, F&& f );
template<class T, class E, class F, class R = ...>
result<T, E>& operator&=( result<T, E>& r, F&& f );
} // namespace system
} // namespace boost
@@ -1713,7 +1745,7 @@ Effects: ::
ensures that `*this` holds the error `E( std::forward<A>(a)... )`.
- Otherwise, this constructor does not participate in overload resolution.
Remarks: ::
This constructor is only enabled when `sizeof...(T) > 0`.
This constructor is only enabled when `sizeof...(A) > 0`.
```
template<class... A>
@@ -1747,7 +1779,7 @@ template<class T2, class E2>
* {blank}
+
Ensures: ::
If `r2.has_value()` is `true`, `*this` holds the value `T( *r2 )`, otherwise `*this` holds the value `E( r2.error() )`.
If `r2.has_value()` is `true`, `*this` holds the value `T( *r2 )`, otherwise `*this` holds the error `E( r2.error() )`.
Remarks: ::
This constructor is only enabled when `std::is_convertible<T2, T>::value && std::is_convertible<E2, E>::value` is `true`.
@@ -1759,7 +1791,7 @@ template<class T2, class E2>
* {blank}
+
Ensures: ::
If `r2.has_value()` is `true`, `*this` holds the value `T( std::move( *r2 ) )`, otherwise `*this` holds the value `E( r2.error() )`.
If `r2.has_value()` is `true`, `*this` holds the value `T( std::move( *r2 ) )`, otherwise `*this` holds the error `E( r2.error() )`.
Remarks: ::
This constructor is only enabled when `std::is_convertible<T2, T>::value && std::is_convertible<E2, E>::value` is `true`.
@@ -1961,6 +1993,9 @@ public:
template<class... A>
constexpr result( in_place_error_t, A&&... a );
template<class E2>
constexpr result( result<void, E2> const& r2 );
// queries
constexpr bool has_value() const noexcept;
@@ -2032,7 +2067,7 @@ Effects: ::
ensures that `*this` holds the error `E( std::forward<A>(a)... )`.
- Otherwise, this constructor does not participate in overload resolution.
Remarks: ::
This constructor is only enabled when `sizeof...(T) > 0`.
This constructor is only enabled when `sizeof...(A) > 0`.
```
template<class... A>
@@ -2056,6 +2091,18 @@ Ensures: ::
Remarks: ::
This constructor is only enabled when `std::is_constructible<E, A...>::value` is `true`.
```
template<class E2>
constexpr result( result<void, E2> const& r2 );
```
[none]
* {blank}
+
Ensures: ::
If `r2.has_value()` is `true`, `*this` holds an unspecified value, otherwise `*this` holds the error `E( r2.error() )`.
Remarks: ::
This constructor is only enabled when `std::is_convertible<E2, E>::value` is `true`.
#### Queries
```
@@ -2201,6 +2248,533 @@ Effects: ::
Returns: ::
`os`.
### result<U&, E>
```
namespace boost {
namespace system {
template<class U, class E> class result<U&, E>
{
public:
using value_type = U&;
using error_type = E;
static constexpr in_place_value_t in_place_value{};
static constexpr in_place_error_t in_place_error{};
// constructors
template<class A>
constexpr result( A&& a ) noexcept;
template<class... A>
constexpr result( A&&... a );
template<class A>
constexpr result( in_place_value_t, A&& a ) noexcept;
template<class... A>
constexpr result( in_place_error_t, A&&... a );
template<class U2, class E2>
constexpr result( result<U2&, E2> const& r2 );
// queries
constexpr bool has_value() const noexcept;
constexpr bool has_error() const noexcept;
constexpr explicit operator bool() const noexcept;
// checked value access
constexpr U& value( boost::source_location const & loc =
BOOST_CURRENT_LOCATION ) const;
// unchecked value access
constexpr U* operator->() const noexcept;
constexpr U& operator*() const noexcept;
// error access
constexpr E error() const &;
constexpr E error() &&;
// emplace
template<class A>
constexpr U& emplace( A&& a ) noexcept;
// swap
constexpr void swap( result& r );
friend constexpr void swap( result & r1, result & r2 );
// equality
friend constexpr bool operator==( result const & r1, result const & r2 );
friend constexpr bool operator!=( result const & r1, result const & r2 );
};
} // namespace system
} // namespace boost
```
#### Constructors
```
template<class A>
constexpr result( A&& a ) noexcept;
```
[none]
* {blank}
+
Ensures: ::
`*this` holds the reference `static_cast<U&>( std::forward<A>(a) )`.
Remarks: ::
This constructor is only enabled when `A` is `B&` and `std::is_convertible<B*, U*>::value` is `true`.
```
template<class... A>
constexpr result( A&&... a );
```
[none]
* {blank}
+
Effects: ::
- If `std::is_constructible<E, A...>::value && !std::is_constructible<U&, A...>::value`,
ensures that `*this` holds the error `E( std::forward<A>(a)... )`.
- Otherwise, this constructor does not participate in overload resolution.
Remarks: ::
This constructor is only enabled when `sizeof...(A) > 0`.
```
template<class A>
constexpr result( in_place_value_t, A&& a ) noexcept;
```
[none]
* {blank}
+
Ensures: ::
`*this` holds the reference `static_cast<U&>( std::forward<A>(a) )`.
Remarks: ::
This constructor is only enabled when `A` is `B&` and `std::is_convertible<B*, U*>::value` is `true`.
```
template<class... A>
constexpr result( in_place_error_t, A&&... a );
```
[none]
* {blank}
+
Ensures: ::
`*this` holds the error `E( std::forward<A>(a)... )`.
Remarks: ::
This constructor is only enabled when `std::is_constructible<E, A...>::value` is `true`.
```
template<class U2, class E2>
constexpr result( result<U2&, E2> const& r2 );
```
[none]
* {blank}
+
Ensures: ::
If `r2.has_value()` is `true`, `*this` holds the reference `static_cast<U&>( *r2 )`, otherwise `*this` holds the error `E( r2.error() )`.
Remarks: ::
This constructor is only enabled when `std::is_convertible<U2*, U*>::value && std::is_convertible<E2, E>::value` is `true`.
#### Queries
```
constexpr bool has_value() const noexcept;
```
[none]
* {blank}
+
Returns: ::
`true` when `*this` holds a value, `false` otherwise.
```
constexpr bool has_error() const noexcept;
```
[none]
* {blank}
+
Returns: ::
`!has_value()`.
```
constexpr explicit operator bool() const noexcept;
```
[none]
* {blank}
+
Returns: ::
`has_value()`.
#### Checked Value Access
```
constexpr U& value(
boost::source_location const & loc = BOOST_CURRENT_LOCATION ) const;
```
[none]
* {blank}
+
Effects: ::
If `*this` holds a reference, returns it. Otherwise,
calls `throw_exception_from_error`, passing it a reference to
the held error, and `loc`.
#### Unchecked Value Access
```
constexpr U* operator->() const noexcept;
```
[none]
* {blank}
+
Returns: ::
If `*this` holds a reference, a pointer to its referent. Otherwise, `nullptr`.
```
constexpr U& operator*() const noexcept;
```
[none]
* {blank}
+
Requires: :: `*this` holds a reference.
Returns: ::
`*operator\->()`.
#### Error Access
```
constexpr E error() const &;
constexpr E error() &&;
```
[none]
* {blank}
+
Effects: ::
If `*this` holds an error, returns it. Otherwise, returns `E()`.
#### emplace
```
template<class A>
constexpr U& emplace( A&& a ) noexcept;
```
[none]
* {blank}
+
Ensures: ::
`*this` holds the reference `static_cast<U&>( std::forward<A>(a)... )`.
Returns: ::
The contained reference.
Remarks: ::
This function is only enabled when `A` is `B&` and `std::is_convertible<B*, U*>::value` is `true`.
#### swap
```
constexpr void swap( result& r );
```
[none]
* {blank}
+
Effects: ::
Exchanges the contents of `*this` and `r`.
```
friend constexpr void swap( result & r1, result & r2 );
```
[none]
* {blank}
+
Effects: ::
Exchanges the contents of `r1` and `r2`.
#### Equality
```
friend constexpr bool operator==( result const & r1, result const & r2 );
```
[none]
* {blank}
+
Effects: ::
- If `r1` holds a reference `t1` and `r2` holds a reference `t2`, returns `t1 == t2`.
- If `r1` holds an error `e1` and `r2` holds an error `e2`, returns `e1 == e2`.
- Otherwise, returns `false`.
```
friend constexpr bool operator!=( result const & r1, result const & r2 );
```
[none]
* {blank}
+
Returns: ::
`!( r1 == r2 )`.
### Chaining
#### operator|
```
template<class T, class E, class U> T operator|( result<T, E> const& r, U&& u );
template<class T, class E, class U> T operator|( result<T, E>&& r, U&& u );
```
[none]
* {blank}
+
Returns the value in `r`, or if `r` contains an error, a default value `u`.
+
Effects: ::
- If `r.has_value()` is `true`, returns `*r`.
- Otherwise, returns `u`.
Remarks: ::
Only enabled when `U` is convertible to `T`.
Example: ::
+
```
result<int> get_server_port(); // can fail
int get_port()
{
return get_server_port() | 443;
}
```
```
template<class T, class E, class F> T operator|( result<T, E> const& r, F&& f );
template<class T, class E, class F> T operator|( result<T, E>&& r, F&& f );
```
[none]
* {blank}
+
Returns the value in `r`, or if `r` contains an error, a default value obtained
by invoking the function `f`.
+
Effects: ::
- If `r.has_value()` is `true`, returns `*r`.
- Otherwise, returns `f()`.
Remarks: ::
Only enabled when `f()` is convertible to `T`.
Example: ::
+
```
result<int> get_server_port(); // can fail
int get_default_port();
int get_port()
{
return get_server_port() | get_default_port;
}
```
+
Note that the right hand side is `get_default_port` and not `get_default_port()`.
This is important; spelled this way, the function `get_default_port` is called
only when `get_server_port_impl()` fails. If it were
+
```
return get_server_port() | get_default_port();
```
+
the function would have been called unconditionally.
+
Another, equivalent, way is to use a lambda
+
```
return get_server_port() | []{ return get_default_port(); };
```
+
which isn't necessary here, but would be needed for more complex expressions.
```
template<class T, class E, class F, class R = ...> R operator|( result<T, E> const& r, F&& f );
template<class T, class E, class F, class R = ...> R operator|( result<T, E>&& r, F&& f );
template<class E, class F, class R = ...> R operator|( result<void, E> const& r, F&& f );
template<class E, class F, class R = ...> R operator|( result<void, E>&& r, F&& f );
```
[none]
* {blank}
+
Returns the value in `r`, or if `r` contains an error, another `result` obtained
by invoking the function `f`.
+
Let `R` be the type of `f()`.
+
Effects: ::
- If `r.has_value()` is `true`, returns `*r`.
- Otherwise, returns `f()`.
Remarks: ::
Only enabled when `R` is an instance of `result` and `T` is convertible to `R::value_type`.
Example: ::
+
```
result<int> get_server_port(); // can fail
result<int> get_default_port(); // can fail
int get_port()
{
return get_server_port() | get_default_port | 443;
}
```
#### operator&
```
template<class T, class E, class F, class U = ...>
result<U, E> operator&( result<T, E> const& r, F&& f );
template<class T, class E, class F, class U = ...>
result<U, E> operator&( result<T, E>&& r, F&& f );
```
[none]
* {blank}
+
Returns the error in `r`, or if `r` contains a value, transforms the value by calling `f` on it.
+
Let `U` be the type of `f(*r)`.
+
Effects: ::
- If `r.has_value()` is `true`, returns `f(*r)`.
- Otherwise, returns `r.error()`.
Remarks: ::
Only enabled when `U` is not an instance of `result`.
Example: ::
+
```
struct currency_type
{
char code_[ 4 ] = {};
};
result<double> get_exchange_rate( currency_type from, currency_type to );
result<double> convert( double amount, currency_type from, currency_type to )
{
return get_exchange_rate( from, to ) & [&](double rate){ return rate * amount; };
}
```
```
template<class T, class E, class F, class R = ...> R operator&( result<T, E> const& r, F&& f );
template<class T, class E, class F, class R = ...> R operator&( result<T, E>&& r, F&& f );
```
[none]
* {blank}
+
Returns the error in `r`, or if `r` contains a value, another `result` obtained
by invoking the function `f` on the value in `r`.
+
Let `R` be the type of `f(*r)`.
+
Effects: ::
- If `r.has_value()` is `true`, returns `f(*r)`.
- Otherwise, returns `r.error()`.
Remarks: ::
Only enabled when `R` is an instance of `result` and `E` is convertible to `R::error_type`.
Example: ::
+
```
struct JsonValue
{
result<JsonValue const&> at( std::size_t i ) const noexcept;
result<JsonValue const&> at( std::string_view key ) const noexcept;
template<class T> result<T> to_number() const noexcept;
};
namespace helpers
{
inline auto at( std::size_t i ) {
return [=](JsonValue const& jv){ return jv.at( i ); }; }
inline auto at( std::string_view key ) {
return [=](JsonValue const& jv){ return jv.at( key ); }; }
template<class T> inline auto to_number() {
return [](JsonValue const& jv){ return jv.to_number<T>(); }; }
} // namespace helpers
int get_port( JsonValue const& config, int def )
{
using namespace helpers;
return config.at( "servers" ) & at( 0 ) & at( "port" ) & to_number<int>() | def;
}
```
#### operator&=
```
template<class T, class E, class F, class U = ...>
result<T, E>& operator&=( result<T, E>& r, F&& f );
```
[none]
* {blank}
+
If `r` contains a value, replaces it with the result of invoking the function `f` on the value in `r`.
+
Let `U` be the type of `f(*r)`.
+
Effects: :: If `r.has_value()` is `true`, assigns `f(*std::move(r))` to `r`.
Returns: :: `r`.
Remarks: ::
Only enabled when `U` is not an instance of `result` and is convertible to `T`.
```
template<class T, class E, class F, class R = ...>
result<T, E>& operator&=( result<T, E>& r, F&& f );
```
[none]
* {blank}
+
If `r` contains a value, replaces `r` with the result of invoking the function `f` on the value in `r`.
+
Let `R` be the type of `f(*r)`.
+
Effects: :: If `r.has_value()` is `true`, assigns `f(*std::move(r))` to `r`.
Returns: :: `r`.
Remarks: ::
Only enabled when `R` is an instance of `result` and is convertible to `result<T, E>`.
Example: ::
+
```
struct JsonValue
{
result<JsonValue const&> at( std::string_view key ) const noexcept;
};
namespace helpers
{
inline auto at( std::string_view key ) {
return [=](JsonValue const& jv){ return jv.at( key ); }; }
} // namespace helpers
result<JsonValue const&> at_path( JsonValue const& jv,
std::initializer_list<std::string_view> path )
{
result<JsonValue const&> r( jv );
using namespace helpers;
for( auto key: path )
{
r &= at( key );
}
return r;
}
```
## <boost/system.hpp>
This convenience header includes all the headers previously described.

View File

@@ -40,13 +40,20 @@ struct mutex
// issues. However, shared_mutex is based on SRWLock and its
// default constructor is constexpr, so we use that instead.
#include <boost/winapi/config.hpp>
// SRWLOCK is not available when targeting Windows XP
#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
#include <shared_mutex>
#if BOOST_MSSTL_VERSION >= 142 || _HAS_SHARED_MUTEX
# define BOOST_SYSTEM_HAS_MSSTL_SHARED_MUTEX
#endif
#endif
#endif // BOOST_MSSTL_VERSION >= 142 || _HAS_SHARED_MUTEX
#endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
#if defined(BOOST_SYSTEM_HAS_MSSTL_SHARED_MUTEX)

View File

@@ -14,7 +14,7 @@
defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) || \
defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR)
BOOST_PRAGMA_MESSAGE("C++03 support is deprecated in Boost.System 1.82 and will be removed in Boost.System 1.84.")
BOOST_PRAGMA_MESSAGE("C++03 support was deprecated in Boost.System 1.82 and will be removed in Boost.System 1.85.")
#endif

View File

@@ -450,6 +450,13 @@ public:
}
};
#if defined(BOOST_NO_CXX17_INLINE_VARIABLES)
template<class T, class E> constexpr in_place_value_t result<T, E>::in_place_value;
template<class T, class E> constexpr in_place_error_t result<T, E>::in_place_error;
#endif
template<class Ch, class Tr, class T, class E> std::basic_ostream<Ch, Tr>& operator<<( std::basic_ostream<Ch, Tr>& os, result<T, E> const & r )
{
if( r.has_value() )
@@ -538,6 +545,23 @@ public:
{
}
// converting
template<class E2, class En = typename std::enable_if<
std::is_convertible<E2, E>::value
>::type>
BOOST_CXX14_CONSTEXPR result( result<void, E2> const& r2 )
noexcept(
std::is_nothrow_constructible<E, E2>::value &&
std::is_nothrow_default_constructible<E2>::value &&
std::is_nothrow_copy_constructible<E2>::value )
: v_( in_place_error, r2.error() )
{
if( r2 )
{
this->emplace();
}
}
// queries
constexpr bool has_value() const noexcept
@@ -635,6 +659,13 @@ public:
}
};
#if defined(BOOST_NO_CXX17_INLINE_VARIABLES)
template<class E> constexpr in_place_value_t result<void, E>::in_place_value;
template<class E> constexpr in_place_error_t result<void, E>::in_place_error;
#endif
template<class Ch, class Tr, class E> std::basic_ostream<Ch, Tr>& operator<<( std::basic_ostream<Ch, Tr>& os, result<void, E> const & r )
{
if( r.has_value() )
@@ -649,6 +680,502 @@ template<class Ch, class Tr, class E> std::basic_ostream<Ch, Tr>& operator<<( st
return os;
}
// result<T&, E>
namespace detail
{
template<class U, class A> struct reference_to_temporary: std::integral_constant<bool,
!std::is_reference<A>::value ||
!std::is_convertible<typename std::remove_reference<A>::type*, U*>::value
> {};
} // namespace detail
template<class U, class E> class result<U&, E>
{
private:
variant2::variant<U*, E> v_;
public:
using value_type = U&;
using error_type = E;
static constexpr in_place_value_t in_place_value{};
static constexpr in_place_error_t in_place_error{};
public:
// constructors
// implicit, value
template<class A, typename std::enable_if<
std::is_convertible<A, U&>::value &&
!detail::reference_to_temporary<U, A>::value &&
!std::is_convertible<A, E>::value, int>::type = 0>
constexpr result( A&& a )
noexcept( std::is_nothrow_constructible<U&, A>::value )
: v_( in_place_value, &static_cast<U&>( std::forward<A>(a) ) )
{
}
// implicit, error
template<class A = E, class = void, typename std::enable_if<
std::is_convertible<A, E>::value &&
!std::is_convertible<A, U&>::value, int>::type = 0>
constexpr result( A&& a )
noexcept( std::is_nothrow_constructible<E, A>::value )
: v_( in_place_error, std::forward<A>(a) )
{
}
// explicit, value
template<class A, class En = typename std::enable_if<
detail::is_constructible<U&, A>::value &&
!std::is_convertible<A, U&>::value &&
!detail::reference_to_temporary<U, A>::value &&
!detail::is_constructible<E, A>::value
>::type>
explicit constexpr result( A&& a )
noexcept( std::is_nothrow_constructible<U&, A>::value )
: v_( in_place_value, &static_cast<U&>( std::forward<A>(a) ) )
{
}
// explicit, error
template<class... A, class En2 = void, class En = typename std::enable_if<
!detail::is_constructible<U&, A...>::value &&
detail::is_constructible<E, A...>::value &&
sizeof...(A) >= 1
>::type>
explicit constexpr result( A&&... a )
noexcept( std::is_nothrow_constructible<E, A...>::value )
: v_( in_place_error, std::forward<A>(a)... )
{
}
// tagged, value
template<class A, class En = typename std::enable_if<
std::is_constructible<U&, A>::value &&
!detail::reference_to_temporary<U, A>::value
>::type>
constexpr result( in_place_value_t, A&& a )
noexcept( std::is_nothrow_constructible<U&, A>::value )
: v_( in_place_value, &static_cast<U&>( std::forward<A>(a) ) )
{
}
// tagged, error
template<class... A, class En = typename std::enable_if<
std::is_constructible<E, A...>::value
>::type>
constexpr result( in_place_error_t, A&&... a )
noexcept( std::is_nothrow_constructible<E, A...>::value )
: v_( in_place_error, std::forward<A>(a)... )
{
}
// converting
template<class U2, class E2, class En = typename std::enable_if<
std::is_convertible<U2&, U&>::value &&
!detail::reference_to_temporary<U, U2&>::value &&
std::is_convertible<E2, E>::value &&
!std::is_convertible<result<U2&, E2> const&, U&>::value
>::type>
BOOST_CXX14_CONSTEXPR result( result<U2&, E2> const& r2 )
noexcept(
std::is_nothrow_constructible<U&, U2&>::value &&
std::is_nothrow_constructible<E, E2>::value &&
std::is_nothrow_default_constructible<E2>::value &&
std::is_nothrow_copy_constructible<E2>::value )
: v_( in_place_error, r2.error() )
{
if( r2 )
{
this->emplace( *r2 );
}
}
// queries
constexpr bool has_value() const noexcept
{
return v_.index() == 0;
}
constexpr bool has_error() const noexcept
{
return v_.index() == 1;
}
constexpr explicit operator bool() const noexcept
{
return v_.index() == 0;
}
// checked value access
BOOST_CXX14_CONSTEXPR U& value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) const
{
if( has_value() )
{
return *variant2::unsafe_get<0>( v_ );
}
else
{
throw_exception_from_error( variant2::unsafe_get<1>( v_ ), loc );
}
}
// unchecked value access
BOOST_CXX14_CONSTEXPR U* operator->() const noexcept
{
return has_value()? variant2::unsafe_get<0>( v_ ): 0;
}
BOOST_CXX14_CONSTEXPR U& operator*() const noexcept
{
U* p = operator->();
BOOST_ASSERT( p != 0 );
return *p;
}
// error access
constexpr E error() const &
noexcept( std::is_nothrow_default_constructible<E>::value && std::is_nothrow_copy_constructible<E>::value )
{
return has_error()? variant2::unsafe_get<1>( v_ ): E();
}
BOOST_CXX14_CONSTEXPR E error() &&
noexcept( std::is_nothrow_default_constructible<E>::value && std::is_nothrow_move_constructible<E>::value )
{
return has_error()? std::move( variant2::unsafe_get<1>( v_ ) ): E();
}
// emplace
template<class A, class En = typename std::enable_if<
detail::is_constructible<U&, A>::value &&
!detail::reference_to_temporary<U, A>::value
>::type>
BOOST_CXX14_CONSTEXPR U& emplace( A&& a )
{
return *v_.template emplace<0>( &static_cast<U&>( a ) );
}
// swap
BOOST_CXX14_CONSTEXPR void swap( result& r )
noexcept( noexcept( v_.swap( r.v_ ) ) )
{
v_.swap( r.v_ );
}
friend BOOST_CXX14_CONSTEXPR void swap( result & r1, result & r2 )
noexcept( noexcept( r1.swap( r2 ) ) )
{
r1.swap( r2 );
}
// equality
friend constexpr bool operator==( result const & r1, result const & r2 )
noexcept( noexcept( r1 && r2? *r1 == *r2: r1.v_ == r2.v_ ) )
{
return r1 && r2? *r1 == *r2: r1.v_ == r2.v_;
}
friend constexpr bool operator!=( result const & r1, result const & r2 )
noexcept( noexcept( !( r1 == r2 ) ) )
{
return !( r1 == r2 );
}
};
#if defined(BOOST_NO_CXX17_INLINE_VARIABLES)
template<class U, class E> constexpr in_place_value_t result<U&, E>::in_place_value;
template<class U, class E> constexpr in_place_error_t result<U&, E>::in_place_error;
#endif
// operator|
namespace detail
{
// is_value_convertible_to
template<class T, class U> struct is_value_convertible_to: std::is_convertible<T, U>
{
};
template<class T, class U> struct is_value_convertible_to<T, U&>:
std::integral_constant<bool,
std::is_lvalue_reference<T>::value &&
std::is_convertible<typename std::remove_reference<T>::type*, U*>::value>
{
};
// is_result
template<class T> struct is_result: std::false_type {};
template<class T, class E> struct is_result< result<T, E> >: std::true_type {};
} // namespace detail
// result | value
template<class T, class E, class U,
class En = typename std::enable_if<detail::is_value_convertible_to<U, T>::value>::type
>
T operator|( result<T, E> const& r, U&& u )
{
if( r )
{
return *r;
}
else
{
return std::forward<U>( u );
}
}
template<class T, class E, class U,
class En = typename std::enable_if<detail::is_value_convertible_to<U, T>::value>::type
>
T operator|( result<T, E>&& r, U&& u )
{
if( r )
{
return *std::move( r );
}
else
{
return std::forward<U>( u );
}
}
// result | nullary-returning-value
template<class T, class E, class F,
class U = decltype( std::declval<F>()() ),
class En = typename std::enable_if<detail::is_value_convertible_to<U, T>::value>::type
>
T operator|( result<T, E> const& r, F&& f )
{
if( r )
{
return *r;
}
else
{
return std::forward<F>( f )();
}
}
template<class T, class E, class F,
class U = decltype( std::declval<F>()() ),
class En = typename std::enable_if<detail::is_value_convertible_to<U, T>::value>::type
>
T operator|( result<T, E>&& r, F&& f )
{
if( r )
{
return *std::move( r );
}
else
{
return std::forward<F>( f )();
}
}
// result | nullary-returning-result
template<class T, class E, class F,
class U = decltype( std::declval<F>()() ),
class En1 = typename std::enable_if<detail::is_result<U>::value>::type,
class En2 = typename std::enable_if<detail::is_value_convertible_to<T, typename U::value_type>::value>::type
>
U operator|( result<T, E> const& r, F&& f )
{
if( r )
{
return *r;
}
else
{
return std::forward<F>( f )();
}
}
template<class T, class E, class F,
class U = decltype( std::declval<F>()() ),
class En1 = typename std::enable_if<detail::is_result<U>::value>::type,
class En2 = typename std::enable_if<detail::is_value_convertible_to<T, typename U::value_type>::value>::type
>
U operator|( result<T, E>&& r, F&& f )
{
if( r )
{
return *std::move( r );
}
else
{
return std::forward<F>( f )();
}
}
template<class E, class F,
class U = decltype( std::declval<F>()() ),
class En1 = typename std::enable_if<detail::is_result<U>::value>::type,
class En2 = typename std::enable_if<std::is_void<typename U::value_type>::value>::type
>
U operator|( result<void, E> const& r, F&& f )
{
if( r )
{
return {};
}
else
{
return std::forward<F>( f )();
}
}
template<class E, class F,
class U = decltype( std::declval<F>()() ),
class En1 = typename std::enable_if<detail::is_result<U>::value>::type,
class En2 = typename std::enable_if<std::is_void<typename U::value_type>::value>::type
>
U operator|( result<void, E>&& r, F&& f )
{
if( r )
{
return {};
}
else
{
return std::forward<F>( f )();
}
}
// operator&
// result & unary-returning-value
template<class T, class E, class F,
class U = decltype( std::declval<F>()( std::declval<T const&>() ) ),
class En = typename std::enable_if<!detail::is_result<U>::value>::type
>
result<U, E> operator&( result<T, E> const& r, F&& f )
{
if( r.has_error() )
{
return r.error();
}
else
{
return std::forward<F>( f )( *r );
}
}
template<class T, class E, class F,
class U = decltype( std::declval<F>()( std::declval<T>() ) ),
class En = typename std::enable_if<!detail::is_result<U>::value>::type
>
result<U, E> operator&( result<T, E>&& r, F&& f )
{
if( r.has_error() )
{
return r.error();
}
else
{
return std::forward<F>( f )( *std::move( r ) );
}
}
// result & unary-returning-result
template<class T, class E, class F,
class U = decltype( std::declval<F>()( std::declval<T const&>() ) ),
class En1 = typename std::enable_if<detail::is_result<U>::value>::type,
class En2 = typename std::enable_if<std::is_convertible<E, typename U::error_type>::value>::type
>
U operator&( result<T, E> const& r, F&& f )
{
if( r.has_error() )
{
return r.error();
}
else
{
return std::forward<F>( f )( *r );
}
}
template<class T, class E, class F,
class U = decltype( std::declval<F>()( std::declval<T>() ) ),
class En1 = typename std::enable_if<detail::is_result<U>::value>::type,
class En2 = typename std::enable_if<std::is_convertible<E, typename U::error_type>::value>::type
>
U operator&( result<T, E>&& r, F&& f )
{
if( r.has_error() )
{
return r.error();
}
else
{
return std::forward<F>( f )( *std::move( r ) );
}
}
// operator&=
// result &= unary-returning-value
template<class T, class E, class F,
class U = decltype( std::declval<F>()( std::declval<T>() ) ),
class En1 = typename std::enable_if<!detail::is_result<U>::value>::type,
class En2 = typename std::enable_if<detail::is_value_convertible_to<U, T>::value>::type
>
result<T, E>& operator&=( result<T, E>& r, F&& f )
{
if( r )
{
r = std::forward<F>( f )( *std::move( r ) );
}
return r;
}
// result &= unary-returning-result
template<class T, class E, class F,
class U = decltype( std::declval<F>()( std::declval<T>() ) ),
class En1 = typename std::enable_if<detail::is_result<U>::value>::type,
class En2 = typename std::enable_if<detail::is_value_convertible_to<typename U::value_type, T>::value>::type,
class En3 = typename std::enable_if<std::is_convertible<typename U::error_type, E>::value>::type
>
result<T, E>& operator&=( result<T, E>& r, F&& f )
{
if( r )
{
r = std::forward<F>( f )( *std::move( r ) );
}
return r;
}
} // namespace system
} // namespace boost

View File

@@ -164,3 +164,16 @@ boost_test(TYPE run SOURCES result_error_construct4.cpp)
boost_test(TYPE run SOURCES result_value_construct4.cpp)
boost_test(TYPE run SOURCES result_value_construct5.cpp)
boost_test(TYPE run SOURCES result_error_move.cpp)
boost_test(TYPE run SOURCES result_value_construct6.cpp)
boost_test(TYPE run SOURCES result_value_construct7.cpp)
boost_test(TYPE run SOURCES result_error_construct5.cpp)
boost_test(TYPE run SOURCES result_or_value.cpp)
boost_test(TYPE compile-fail SOURCES result_or_value_fail.cpp)
boost_test(TYPE compile-fail SOURCES result_or_value_fail2.cpp)
boost_test(TYPE run SOURCES result_or_fn0v.cpp)
boost_test(TYPE run SOURCES result_or_fn0r.cpp)
boost_test(TYPE run SOURCES result_and_fn1v.cpp)
boost_test(TYPE run SOURCES result_and_fn1r.cpp)
boost_test(TYPE run SOURCES result_and_eq_fn1v.cpp)
boost_test(TYPE run SOURCES result_and_eq_fn1r.cpp)
boost_test(TYPE run SOURCES result_in_place_use.cpp)

View File

@@ -194,3 +194,16 @@ run result_error_construct4.cpp : : : $(CPP11) ;
run result_value_construct4.cpp : : : $(CPP11) ;
run result_value_construct5.cpp : : : $(CPP11) ;
run result_error_move.cpp : : : $(CPP11) ;
run result_value_construct6.cpp : : : $(CPP11) ;
run result_value_construct7.cpp : : : $(CPP11) ;
run result_error_construct5.cpp : : : $(CPP11) ;
run result_or_value.cpp : : : $(CPP11) ;
compile-fail result_or_value_fail.cpp : $(CPP11) ;
compile-fail result_or_value_fail2.cpp : $(CPP11) ;
run result_or_fn0v.cpp : : : $(CPP11) ;
run result_or_fn0r.cpp : : : $(CPP11) ;
run result_and_fn1v.cpp : : : $(CPP11) ;
run result_and_fn1r.cpp : : : $(CPP11) ;
run result_and_eq_fn1v.cpp : : : $(CPP11) ;
run result_and_eq_fn1r.cpp : : : $(CPP11) ;
run result_in_place_use.cpp : : : $(CPP11) ;

126
test/result_and_eq_fn1r.cpp Normal file
View File

@@ -0,0 +1,126 @@
// Copyright 2017, 2021, 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/system/result.hpp>
#include <boost/core/lightweight_test.hpp>
using namespace boost::system;
struct X
{
int v_;
};
struct Y
{
int v_;
explicit Y( int v ): v_( v ) {}
Y( X x ): v_( x.v_) {}
Y( Y const& ) = delete;
Y& operator=( Y const& ) = delete;
Y( Y&& r ): v_( r.v_ )
{
r.v_ = 0;
}
Y& operator=( Y&& r )
{
if( &r != this )
{
v_ = r.v_;
r.v_ = 0;
}
return *this;
}
};
struct E
{
};
struct E2
{
E2() {}
E2( E ) {}
};
result<int, E> fi( int x )
{
return 2 * x + 1;
}
result<int, E2> fi2( int )
{
return E2();
}
result<X, E> fy( Y y )
{
return X{ 2 * y.v_ + 1 };
}
result<Y, E2> fy2( Y )
{
return E2();
}
result<int&, E> fri( int& )
{
static int x = 2;
return x;
}
result<int&, E2> fri2( int& )
{
return E2();
}
int main()
{
{
result<int, E2> r( 1 );
r &= fi;
BOOST_TEST( r.has_value() ) && BOOST_TEST_EQ( *r, 3 );
r &= fi2;
BOOST_TEST( r.has_error() );
r &= fi;
BOOST_TEST( r.has_error() );
}
{
result<Y, E2> r( in_place_value, 1 );
r &= fy;
BOOST_TEST( r.has_value() ) && BOOST_TEST_EQ( r->v_, 3 );
r &= fy2;
BOOST_TEST( r.has_error() );
r &= fy;
BOOST_TEST( r.has_error() );
}
{
int x1 = 1;
result<int&, E2> r( x1 );
r &= fri;
BOOST_TEST( r.has_value() ) && BOOST_TEST_EQ( &*r, &*fri( x1 ) );
r &= fri2;
BOOST_TEST( r.has_error() );
r &= fri;
BOOST_TEST( r.has_error() );
}
return boost::report_errors();
}

114
test/result_and_eq_fn1v.cpp Normal file
View File

@@ -0,0 +1,114 @@
// Copyright 2017, 2021, 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/system/result.hpp>
#include <boost/core/lightweight_test.hpp>
using namespace boost::system;
struct X
{
int v_;
};
struct Y
{
int v_;
explicit Y( int v ): v_( v ) {}
Y( X x ): v_( x.v_) {}
Y( Y const& ) = delete;
Y& operator=( Y const& ) = delete;
Y( Y&& r ): v_( r.v_ )
{
r.v_ = 0;
}
Y& operator=( Y&& r )
{
if( &r != this )
{
v_ = r.v_;
r.v_ = 0;
}
return *this;
}
};
struct E
{
};
int f( int x )
{
return x * 2 + 1;
}
X g( Y y )
{
return X{ y.v_ * 2 + 1 };
}
int& h( int& )
{
static int x = 2;
return x;
}
int main()
{
{
result<int> r( 1 );
r &= f;
BOOST_TEST( r.has_value() ) && BOOST_TEST_EQ( *r, 3 );
}
{
result<int, E> r( in_place_error );
r &= f;
BOOST_TEST( r.has_error() );
}
{
result<Y> r( in_place_value, 1 );
r &= g;
BOOST_TEST( r.has_value() ) && BOOST_TEST_EQ( r->v_, 3 );
}
{
result<Y, E> r( in_place_error );
r &= g;
BOOST_TEST( r.has_error() );
}
{
int x1 = 1;
result<int&> r( x1 );
r &= h;
BOOST_TEST( r.has_value() ) && BOOST_TEST_EQ( &*r, &h( x1 ) );
}
{
result<int&, E> r( in_place_error );
r &= h;
BOOST_TEST( r.has_error() );
}
return boost::report_errors();
}

347
test/result_and_fn1r.cpp Normal file
View File

@@ -0,0 +1,347 @@
// Copyright 2017, 2021, 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/system/result.hpp>
#include <boost/core/lightweight_test.hpp>
using namespace boost::system;
struct X
{
int v_;
};
struct Y
{
int v_;
explicit Y( int v ): v_( v ) {}
Y( X x ): v_( x.v_) {}
Y( Y const& ) = delete;
Y& operator=( Y const& ) = delete;
Y( Y&& r ): v_( r.v_ )
{
r.v_ = 0;
}
Y& operator=( Y&& ) = delete;
};
struct E
{
};
struct E2
{
E2() {}
E2( E ) {}
};
result<int, E2> fi( int x )
{
return 2 * x + 1;
}
result<int, E2> fi2( int )
{
return E2();
}
result<void, E2> fi3( int )
{
return {};
}
result<X, E2> fy( Y y )
{
return X{ 2 * y.v_ + 1 };
}
result<X, E2> fy2( Y )
{
return E2();
}
result<void, E2> fy3( Y )
{
return {};
}
result<int, E2> fri( int& x )
{
return x * 2 + 1;
}
result<int&, E2> fri2( int& )
{
return E2();
}
result<void, E2> fri3( int& )
{
return {};
}
int main()
{
{
result<int, E> r( 1 );
{
result<int, E2> r2 = r & fi;
BOOST_TEST( r2.has_value() ) && BOOST_TEST_EQ( *r2, 3 );
}
{
result<int, E2> r2 = r & fi2;
BOOST_TEST( r2.has_error() );
}
{
result<void, E2> r2 = r & fi3;
BOOST_TEST( r2.has_value() );
}
}
{
result<int, E> const r( 1 );
{
result<int, E2> r2 = r & fi;
BOOST_TEST( r2.has_value() ) && BOOST_TEST_EQ( *r2, 3 );
}
{
result<int, E2> r2 = r & fi2;
BOOST_TEST( r2.has_error() );
}
{
result<void, E2> r2 = r & fi3;
BOOST_TEST( r2.has_value() );
}
}
{
result<int, E2> r2 = result<int, E>( 1 ) & fi;
BOOST_TEST( r2.has_value() ) && BOOST_TEST_EQ( *r2, 3 );
}
{
result<int, E2> r2 = result<int, E>( 1 ) & fi2;
BOOST_TEST( r2.has_error() );
}
{
result<void, E2> r2 = result<int, E>( 1 ) & fi3;
BOOST_TEST( r2.has_value() );
}
{
result<int, E> r( in_place_error );
{
result<int, E2> r2 = r & fi;
BOOST_TEST( r2.has_error() );
}
{
result<int, E2> r2 = r & fi2;
BOOST_TEST( r2.has_error() );
}
{
result<void, E2> r2 = r & fi3;
BOOST_TEST( r2.has_error() );
}
}
{
result<int, E> const r( in_place_error );
{
result<int, E2> r2 = r & fi;
BOOST_TEST( r2.has_error() );
}
{
result<int, E2> r2 = r & fi2;
BOOST_TEST( r2.has_error() );
}
{
result<void, E2> r2 = r & fi3;
BOOST_TEST( r2.has_error() );
}
}
{
result<int, E2> r2 = result<int, E>( in_place_error ) & fi;
BOOST_TEST( r2.has_error() );
}
{
result<int, E2> r2 = result<int, E>( in_place_error ) & fi2;
BOOST_TEST( r2.has_error() );
}
{
result<void, E2> r2 = result<int, E>( in_place_error ) & fi3;
BOOST_TEST( r2.has_error() );
}
{
result<X, E2> r2 = result<Y, E>( in_place_value, 1 ) & fy;
BOOST_TEST( r2.has_value() ) && BOOST_TEST_EQ( r2->v_, 3 );
}
{
result<X, E2> r2 = result<Y, E>( in_place_value, 1 ) & fy2;
BOOST_TEST( r2.has_error() );
}
{
result<void, E2> r2 = result<Y, E>( in_place_value, 1 ) & fy3;
BOOST_TEST( r2.has_value() );
}
{
result<X, E2> r2 = result<Y, E>( in_place_error ) & fy;
BOOST_TEST( r2.has_error() );
}
{
result<X, E2> r2 = result<Y, E>( in_place_error ) & fy2;
BOOST_TEST( r2.has_error() );
}
{
result<void, E2> r2 = result<Y, E>( in_place_error ) & fy3;
BOOST_TEST( r2.has_error() );
}
{
int x1 = 1;
result<int&, E> r( x1 );
{
result<int, E2> r2 = r & fri;
BOOST_TEST( r2.has_value() ) && BOOST_TEST_EQ( *r2, 3 );
}
{
result<int&, E2> r2 = r & fri2;
BOOST_TEST( r2.has_error() );
}
{
result<void, E2> r2 = r & fri3;
BOOST_TEST( r2.has_value() );
}
}
{
int x1 = 1;
result<int&, E> const r( x1 );
{
result<int, E2> r2 = r & fri;
BOOST_TEST( r2.has_value() ) && BOOST_TEST_EQ( *r2, 3 );
}
{
result<int&, E2> r2 = r & fri2;
BOOST_TEST( r2.has_error() );
}
{
result<void, E2> r2 = r & fri3;
BOOST_TEST( r2.has_value() );
}
}
{
int x1 = 1;
result<int, E2> r2 = result<int&, E>( x1 ) & fri;
BOOST_TEST( r2.has_value() ) && BOOST_TEST_EQ( *r2, 3 );
}
{
int x1 = 1;
result<int&, E2> r2 = result<int&, E>( x1 ) & fri2;
BOOST_TEST( r2.has_error() );
}
{
int x1 = 1;
result<void, E2> r2 = result<int&, E>( x1 ) & fri3;
BOOST_TEST( r2.has_value() );
}
{
result<int&, E> r( in_place_error );
{
result<int, E2> r2 = r & fri;
BOOST_TEST( r2.has_error() );
}
{
result<int&, E2> r2 = r & fri2;
BOOST_TEST( r2.has_error() );
}
{
result<void, E2> r2 = r & fri3;
BOOST_TEST( r2.has_error() );
}
}
{
result<int&, E> const r( in_place_error );
{
result<int, E2> r2 = r & fri;
BOOST_TEST( r2.has_error() );
}
{
result<int&, E2> r2 = r & fri2;
BOOST_TEST( r2.has_error() );
}
{
result<void, E2> r2 = r & fri3;
BOOST_TEST( r2.has_error() );
}
}
{
result<int, E2> r2 = result<int&, E>( in_place_error ) & fri;
BOOST_TEST( r2.has_error() );
}
{
result<int&, E2> r2 = result<int&, E>( in_place_error ) & fri2;
BOOST_TEST( r2.has_error() );
}
{
result<void, E2> r2 = result<int&, E>( in_place_error ) & fri3;
BOOST_TEST( r2.has_error() );
}
return boost::report_errors();
}

158
test/result_and_fn1v.cpp Normal file
View File

@@ -0,0 +1,158 @@
// Copyright 2017, 2021, 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/system/result.hpp>
#include <boost/core/lightweight_test.hpp>
using namespace boost::system;
struct X
{
int v_;
};
struct Y
{
int v_;
explicit Y( int v ): v_( v ) {}
Y( X x ): v_( x.v_) {}
Y( Y const& ) = delete;
Y& operator=( Y const& ) = delete;
Y( Y&& r ): v_( r.v_ )
{
r.v_ = 0;
}
Y& operator=( Y&& ) = delete;
};
struct E
{
};
int f( int x )
{
return x * 2 + 1;
}
X g( Y y )
{
return X{ y.v_ * 2 + 1 };
}
int& h( int& )
{
static int x = 2;
return x;
}
int main()
{
{
result<int> r( 1 );
result<int> r2 = r & f;
BOOST_TEST( r2.has_value() ) && BOOST_TEST_EQ( *r2, 3 );
}
{
result<int> const r( 1 );
result<int> r2 = r & f;
BOOST_TEST( r2.has_value() ) && BOOST_TEST_EQ( *r2, 3 );
}
{
result<int> r2 = result<int>( 1 ) & f;
BOOST_TEST( r2.has_value() ) && BOOST_TEST_EQ( *r2, 3 );
}
{
result<int, E> r( in_place_error );
result<int, E> r2 = r & f;
BOOST_TEST( r2.has_error() );
}
{
result<int, E> const r( in_place_error );
result<int, E> r2 = r & f;
BOOST_TEST( r2.has_error() );
}
{
result<int, E> r2 = result<int, E>( in_place_error ) & f;
BOOST_TEST( r2.has_error() );
}
{
result<X> r2 = result<Y>( in_place_value, 1 ) & g;
BOOST_TEST( r2.has_value() ) && BOOST_TEST_EQ( r2->v_, 3 );
}
{
result<X, E> r2 = result<Y, E>( in_place_error ) & g;
BOOST_TEST( r2.has_error() );
}
{
int x1 = 1;
result<int&> r( x1 );
result<int&> r2 = r & h;
BOOST_TEST( r2.has_value() ) && BOOST_TEST_EQ( &*r2, &h( x1 ) );
}
{
int x1 = 1;
result<int&> const r( x1 );
result<int&> r2 = r & h;
BOOST_TEST( r2.has_value() ) && BOOST_TEST_EQ( &*r2, &h( x1 ) );
}
{
int x1 = 1;
result<int&> r2 = result<int&>( x1 ) & h;
BOOST_TEST( r2.has_value() ) && BOOST_TEST_EQ( &*r2, &h( x1 ) );
}
{
result<int&, E> r( in_place_error );
result<int&, E> r2 = r & h;
BOOST_TEST( r2.has_error() );
}
{
result<int&, E> const r( in_place_error );
result<int&, E> r2 = r & h;
BOOST_TEST( r2.has_error() );
}
{
result<int&, E> r2 = result<int&, E>( in_place_error ) & h;
BOOST_TEST( r2.has_error() );
}
return boost::report_errors();
}

View File

@@ -181,6 +181,95 @@ int main()
BOOST_TEST_EQ( X::instances, 0 );
//
{
result<void, int> r;
result<void, X> r2 = r;
BOOST_TEST( r2 );
BOOST_TEST_EQ( X::instances, 0 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
result<void, int> const r;
result<void, X> r2 = r;
BOOST_TEST( r2 );
BOOST_TEST_EQ( X::instances, 0 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
result<void, X> r2 = result<void, int>();
BOOST_TEST( r2 );
BOOST_TEST_EQ( X::instances, 0 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
result<void, int> r( 5 );
result<void, X> r2 = r;
BOOST_TEST( !r2 );
BOOST_TEST_EQ( r2.error(), X(5) );
BOOST_TEST_EQ( X::instances, 1 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
result<void, int> const r( 6 );
result<void, X> r2 = r;
BOOST_TEST( !r2 );
BOOST_TEST_EQ( r2.error(), X(6) );
BOOST_TEST_EQ( X::instances, 1 );
}
{
result<void, X> r2 = result<void, int>( 7 );
BOOST_TEST( !r2 );
BOOST_TEST_EQ( r2.error(), X(7) );
BOOST_TEST_EQ( X::instances, 1 );
}
BOOST_TEST_EQ( X::instances, 0 );
//
{
int x = 5;
result<int&> r( x );
result<int const&> r2 = r;
BOOST_TEST( r2 ) && BOOST_TEST_EQ( *r2, 5 );
}
{
int x = 6;
result<int&> const r( x );
result<int const&> r2 = r;
BOOST_TEST( r2 ) && BOOST_TEST_EQ( *r2, 6 );
}
{
int x = 7;
result<int const&> r2 = result<int&>( x );
BOOST_TEST( r2 ) && BOOST_TEST_EQ( *r2, 7 );
}
{
BOOST_TEST_TRAIT_TRUE((std::is_constructible<result<long>, result<int>>));
BOOST_TEST_TRAIT_TRUE((std::is_convertible<result<int>, result<long>>));
@@ -196,6 +285,21 @@ int main()
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<int, void*>, result<int, int>>));
BOOST_TEST_TRAIT_FALSE((std::is_convertible<result<int, int>, result<int, void*>>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<void, void*>, result<void, int>>));
BOOST_TEST_TRAIT_FALSE((std::is_convertible<result<void, int>, result<void, void*>>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<result<int const&>, result<int&>>));
BOOST_TEST_TRAIT_TRUE((std::is_convertible<result<int&>, result<int const&>>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<int const&>, result<int>>));
BOOST_TEST_TRAIT_FALSE((std::is_convertible<result<int>, result<int const&>>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<int const&>, result<long&>>));
BOOST_TEST_TRAIT_FALSE((std::is_convertible<result<long&>, result<int const&>>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<int const&>, result<long const&>>));
BOOST_TEST_TRAIT_FALSE((std::is_convertible<result<long const&>, result<int const&>>));
}
return boost::report_errors();

View File

@@ -682,5 +682,151 @@ int main()
BOOST_TEST_EQ( r, r2 );
}
// reference
{
int x1 = 1;
int x2 = 2;
result<int&> r1( x1 );
result<int&> r2( x2 );
r2 = r1;
BOOST_TEST_EQ( x1, 1 );
BOOST_TEST_EQ( x2, 2 );
BOOST_TEST_EQ( r1, r2 );
BOOST_TEST_EQ( &*r1, &*r2 );
}
{
int const x1 = 1;
int const x2 = 2;
result<int const&> r1( x1 );
result<int const&> r2( x2 );
r2 = r1;
BOOST_TEST_EQ( x1, 1 );
BOOST_TEST_EQ( x2, 2 );
BOOST_TEST_EQ( r1, r2 );
BOOST_TEST_EQ( &*r1, &*r2 );
}
{
int x1 = 1;
result<int&> r1( x1 );
result<int&> r2( ENOENT, generic_category() );
r2 = r1;
BOOST_TEST_EQ( x1, 1 );
BOOST_TEST_EQ( r1, r2 );
BOOST_TEST_EQ( &*r1, &*r2 );
}
{
int x1 = 1;
int x2 = 2;
result<int&> const r1( x1 );
result<int&> r2( x2 );
r2 = r1;
BOOST_TEST_EQ( x1, 1 );
BOOST_TEST_EQ( x2, 2 );
BOOST_TEST_EQ( r1, r2 );
BOOST_TEST_EQ( &*r1, &*r2 );
}
{
int const x1 = 1;
int const x2 = 2;
result<int const &> const r1( x1 );
result<int const &> r2( x2 );
r2 = r1;
BOOST_TEST_EQ( x1, 1 );
BOOST_TEST_EQ( x2, 2 );
BOOST_TEST_EQ( r1, r2 );
BOOST_TEST_EQ( &*r1, &*r2 );
}
{
int x1 = 1;
result<int&> const r1( x1 );
result<int&> r2( ENOENT, generic_category() );
r2 = r1;
BOOST_TEST_EQ( x1, 1 );
BOOST_TEST_EQ( r1, r2 );
BOOST_TEST_EQ( &*r1, &*r2 );
}
{
int x2 = 2;
auto ec = make_error_code( errc::invalid_argument );
result<int&> r1( ec );
result<int&> r2( x2 );
r2 = r1;
BOOST_TEST_EQ( x2, 2 );
BOOST_TEST_EQ( r1, r2 );
}
{
auto ec = make_error_code( errc::invalid_argument );
result<int&> r1( ec );
result<int&> r2( ENOENT, generic_category() );
r2 = r1;
BOOST_TEST_EQ( r1, r2 );
}
{
int x2 = 2;
auto ec = make_error_code( errc::invalid_argument );
result<int&> const r1( ec );
result<int&> r2( x2 );
r2 = r1;
BOOST_TEST_EQ( x2, 2 );
BOOST_TEST_EQ( r1, r2 );
}
{
auto ec = make_error_code( errc::invalid_argument );
result<int&> const r1( ec );
result<int&> r2( ENOENT, generic_category() );
r2 = r1;
BOOST_TEST_EQ( r1, r2 );
}
return boost::report_errors();
}

View File

@@ -145,6 +145,8 @@ int main()
BOOST_TEST_EQ( X::instances, 0 );
//
{
result<void> r;
result<void> r2( r );
@@ -177,5 +179,121 @@ int main()
BOOST_TEST_EQ( r, r2 );
}
//
{
int x1 = 1;
result<int&> r1( x1 );
result<int&> r2( r1 );
BOOST_TEST_EQ( r1, r2 );
BOOST_TEST_EQ( &*r2, &x1 );
}
{
int x1 = 1;
result<int&> const r1( x1 );
result<int&> r2( r1 );
BOOST_TEST_EQ( r1, r2 );
BOOST_TEST_EQ( &*r2, &x1 );
}
{
int const x1 = 1;
result<int const&> r1( x1 );
result<int const&> r2( r1 );
BOOST_TEST_EQ( r1, r2 );
BOOST_TEST_EQ( &*r2, &x1 );
}
{
int const x1 = 1;
result<int const&> const r1( x1 );
result<int const&> r2( r1 );
BOOST_TEST_EQ( r1, r2 );
BOOST_TEST_EQ( &*r2, &x1 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
X x1( 1 );
result<X&> r1( x1 );
result<X&> r2( r1 );
BOOST_TEST_EQ( r1, r2 );
BOOST_TEST_EQ( &*r2, &x1 );
BOOST_TEST_EQ( X::instances, 1 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
X x1( 1 );
result<X&> const r1( x1 );
result<X&> r2( r1 );
BOOST_TEST_EQ( r1, r2 );
BOOST_TEST_EQ( &*r2, &x1 );
BOOST_TEST_EQ( X::instances, 1 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
X const x1( 1 );
result<X const&> r1( x1 );
result<X const&> r2( r1 );
BOOST_TEST_EQ( r1, r2 );
BOOST_TEST_EQ( &*r2, &x1 );
BOOST_TEST_EQ( X::instances, 1 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
X const x1( 1 );
result<X const&> const r1( x1 );
result<X const&> r2( r1 );
BOOST_TEST_EQ( r1, r2 );
BOOST_TEST_EQ( &*r2, &x1 );
BOOST_TEST_EQ( X::instances, 1 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
auto ec = make_error_code( errc::invalid_argument );
result<int&> r1( ec );
result<int&> r2( r1 );
BOOST_TEST_EQ( r1, r2 );
}
{
auto ec = make_error_code( errc::invalid_argument );
result<int&> const r1( ec );
result<int&> r2( r1 );
BOOST_TEST_EQ( r1, r2 );
}
//
return boost::report_errors();
}

View File

@@ -28,6 +28,24 @@ int main()
BOOST_TEST_EQ( r.value(), 0 );
}
{
result<int> r{};
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST_EQ( r.value(), 0 );
}
{
result<int> r = {};
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST_EQ( r.value(), 0 );
}
{
result<X> r;
@@ -35,6 +53,20 @@ int main()
BOOST_TEST( !r.has_error() );
}
{
result<X> r{};
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
}
{
result<X> r = {};
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
}
{
result<void> r;
@@ -42,6 +74,20 @@ int main()
BOOST_TEST( !r.has_error() );
}
{
result<void> r{};
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
}
{
result<void> r = {};
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
}
{
BOOST_TEST_TRAIT_TRUE((std::is_default_constructible<result<int>>));
BOOST_TEST_TRAIT_TRUE((std::is_default_constructible<result<int, int>>));
@@ -52,6 +98,9 @@ int main()
BOOST_TEST_TRAIT_FALSE((std::is_default_constructible<result<Y>>));
BOOST_TEST_TRAIT_FALSE((std::is_default_constructible<result<Y, int>>));
BOOST_TEST_TRAIT_FALSE((std::is_default_constructible<result<int&>>));
BOOST_TEST_TRAIT_FALSE((std::is_default_constructible<result<int&, int>>));
}
return boost::report_errors();

View File

@@ -172,5 +172,47 @@ int main()
BOOST_TEST_EQ( Y::instances, 0 );
}
{
int x1 = 1;
result<int&> r( x1 );
BOOST_TEST( r.has_value() );
BOOST_TEST_EQ( r.value(), 1 );
int x2 = 2;
r.emplace( x2 );
BOOST_TEST( r.has_value() );
BOOST_TEST_EQ( r.value(), 2 );
}
{
result<int&> r( ENOENT, generic_category() );
BOOST_TEST( !r.has_value() );
int x2 = 2;
r.emplace( x2 );
BOOST_TEST( r.has_value() );
BOOST_TEST_EQ( r.value(), 2 );
}
BOOST_TEST_EQ( Y::instances, 0 );
{
result<int&, Y> r( in_place_error );
BOOST_TEST( !r.has_value() );
BOOST_TEST_EQ( Y::instances, 1 );
int x2 = 2;
r.emplace( x2 );
BOOST_TEST( r.has_value() );
BOOST_TEST_EQ( *r, 2 );
BOOST_TEST_EQ( Y::instances, 0 );
}
return boost::report_errors();
}

View File

@@ -149,5 +149,83 @@ int main()
BOOST_TEST_NE( r1, r2 );
}
{
int x1 = 1;
int x2 = 2;
result<int&> r1( x1 );
result<int&> r2( x2 );
BOOST_TEST_EQ( r1, r1 );
BOOST_TEST_NE( r1, r2 );
}
{
int x1 = 1;
int x2 = 1;
result<int&> r1( x1 );
result<int&> r2( x2 );
BOOST_TEST_EQ( r1, r2 );
}
{
result<int&> r1( 1, generic_category() );
result<int&> r2( 2, generic_category() );
BOOST_TEST_EQ( r1, r1 );
BOOST_TEST_NE( r1, r2 );
}
{
int x1 = 1;
result<int&> r1( x1 );
result<int&> r2( 2, generic_category() );
BOOST_TEST_EQ( r1, r1 );
BOOST_TEST_NE( r1, r2 );
}
{
X x1( 1 );
X x2( 2 );
result<X&, Y> r1( x1 );
result<X&, Y> r2( x2 );
BOOST_TEST_EQ( r1, r1 );
BOOST_TEST_NE( r1, r2 );
}
{
X x1( 1 );
X x2( 1 );
result<X&, Y> r1( x1 );
result<X&, Y> r2( x2 );
BOOST_TEST_EQ( r1, r2 );
}
{
result<X&, Y> r1( in_place_error, 1 );
result<X&, Y> r2( in_place_error, 2 );
BOOST_TEST_EQ( r1, r1 );
BOOST_TEST_NE( r1, r2 );
}
{
X x1( 1 );
result<X&, Y> r1( x1 );
result<X&, Y> r2( in_place_error, 2 );
BOOST_TEST_EQ( r1, r1 );
BOOST_TEST_NE( r1, r2 );
}
return boost::report_errors();
}

View File

@@ -19,5 +19,14 @@ int main()
BOOST_TEST_TRAIT_FALSE((std::is_convertible<errc::errc_t, result<bool>>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<bool>, errc::errc_t>));
BOOST_TEST_TRAIT_FALSE((std::is_convertible<errc::errc_t, result<int const&>>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<int const&>, errc::errc_t>));
BOOST_TEST_TRAIT_FALSE((std::is_convertible<errc::errc_t, result<double const&>>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<double const&>, errc::errc_t>));
BOOST_TEST_TRAIT_FALSE((std::is_convertible<errc::errc_t, result<bool const&>>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<bool const&>, errc::errc_t>));
return boost::report_errors();
}

View File

@@ -152,6 +152,8 @@ int main()
BOOST_TEST_EQ( (result<std::string, X>( "s" ).error().v_), 0 );
}
//
{
result<void> r;
@@ -208,5 +210,71 @@ int main()
BOOST_TEST_EQ( result<void>( ec ).error(), ec );
}
//
{
int x1 = 1;
result<int&> r( x1 );
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST_EQ( r.error(), error_code() );
}
{
int x1 = 1;
result<int&> const r( x1 );
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST_EQ( r.error(), error_code() );
}
{
int x1 = 1;
BOOST_TEST( result<int&>( x1 ).has_value() );
BOOST_TEST( !result<int&>( x1 ).has_error() );
BOOST_TEST_EQ( result<int&>( x1 ).error(), error_code() );
}
{
auto ec = make_error_code( errc::invalid_argument );
result<int&> r( ec );
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_EQ( r.error(), ec );
}
{
auto ec = make_error_code( errc::invalid_argument );
result<int&> const r( ec );
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_EQ( r.error(), ec );
}
{
auto ec = make_error_code( errc::invalid_argument );
BOOST_TEST( !result<int&>( ec ).has_value() );
BOOST_TEST( result<int&>( ec ).has_error() );
BOOST_TEST_EQ( result<int&>( ec ).error(), ec );
}
//
return boost::report_errors();
}

View File

@@ -157,5 +157,27 @@ int main()
BOOST_TEST_EQ( r.error(), error_code( EINVAL, generic_category() ) );
}
{
auto ec = make_error_code( errc::invalid_argument );
using R = result<int&>;
R r( R::in_place_error, ec );
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_EQ( r.error(), ec );
}
{
using R = result<int&>;
R r( R::in_place_error, EINVAL, generic_category() );
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_EQ( r.error(), error_code( EINVAL, generic_category() ) );
}
return boost::report_errors();
}

View File

@@ -0,0 +1,160 @@
// Copyright 2017, 2021 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/system/result.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <string>
#include <cerrno>
using namespace boost::system;
struct X
{
static int instances;
int v_;
X(): v_() { ++instances; }
explicit X( int v ): v_( v ) { ++instances; }
X( int v1, int v2 ): v_( v1+v2 ) { ++instances; }
X( int v1, int v2, int v3 ): v_( v1+v2+v3 ) { ++instances; }
X( X const& r ): v_( r.v_ ) { ++instances; }
X& operator=( X const& ) = delete;
~X() { --instances; }
};
int X::instances = 0;
int main()
{
{
auto ec = make_error_code( errc::invalid_argument );
result<int&> r( ec );
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_EQ( r.error(), ec );
}
{
auto ec = make_error_code( errc::invalid_argument );
result<int&> r = ec;
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_EQ( r.error(), ec );
}
{
result<int&> r( EINVAL, generic_category() );
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_EQ( r.error(), error_code( EINVAL, generic_category() ) );
}
{
auto ec = make_error_code( errc::invalid_argument );
result<error_code&> r( in_place_error, ec );
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_EQ( r.error(), ec );
}
{
result<error_code&> r( in_place_error, EINVAL, generic_category() );
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_EQ( r.error(), error_code( EINVAL, generic_category() ) );
}
BOOST_TEST_EQ( X::instances, 0 );
{
result<std::string&, X> r( 1 );
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_EQ( r.error().v_, 1 );
BOOST_TEST_EQ( X::instances, 1 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
result<int&, X> r( 1, 2 );
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_EQ( r.error().v_, 1+2 );
BOOST_TEST_EQ( X::instances, 1 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
result<int&, X> r( 1, 2, 3 );
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_EQ( r.error().v_, 1+2+3 );
BOOST_TEST_EQ( X::instances, 1 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
result<X&, X> r( in_place_error, 1 );
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_EQ( r.error().v_, 1 );
BOOST_TEST_EQ( X::instances, 1 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
BOOST_TEST_TRAIT_TRUE((std::is_constructible<result<int&>, error_code>));
BOOST_TEST_TRAIT_TRUE((std::is_convertible<error_code, result<int&>>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<result<std::string&, X>, int>));
BOOST_TEST_TRAIT_FALSE((std::is_convertible<int, result<std::string&, X>>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<result<int&, X>, int>));
BOOST_TEST_TRAIT_FALSE((std::is_convertible<int, result<int&, X>>));
// There's an ambiguity here between int& and X, but since is_convertible
// is true, is_constructible can't be false.
// BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<int&, X>, int&>));
BOOST_TEST_TRAIT_TRUE((std::is_convertible<int&, result<int&, X>>));
}
return boost::report_errors();
}

View File

@@ -55,7 +55,9 @@ int main()
BOOST_TEST_EQ( (result<std::string, X>( "s" ).error().v_), 0 );
}
{
//
{
result<void, X> r( 1 );
BOOST_TEST( !r.has_value() );
@@ -87,5 +89,45 @@ int main()
BOOST_TEST_EQ( (result<void, X>().error().v_), 0 );
}
//
{
result<double&, X> r( 1 );
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_EQ( std::move( r ).error().v_, 1 );
}
{
BOOST_TEST(( !result<double&, X>( 1 ).has_value() ));
BOOST_TEST(( result<double&, X>( 1 ).has_error() ));
BOOST_TEST_EQ( (result<double&, X>( 1 ).error().v_), 1 );
}
{
double x = 1.0;
result<double&, X> r( x );
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST_EQ( std::move( r ).error().v_, 0 );
}
{
double x = 1.0;
BOOST_TEST(( result<double&, X>( x ).has_value() ));
BOOST_TEST(( !result<double&, X>( x ).has_error() ));
BOOST_TEST_EQ( (result<double&, X>( x ).error().v_), 0 );
}
//
return boost::report_errors();
}

View File

@@ -0,0 +1,22 @@
// Copyright 2023 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/system/result.hpp>
#include <boost/core/lightweight_test.hpp>
template<class T, class U> void test( T const& t, U const& u )
{
BOOST_TEST_NE( static_cast<void const*>( &t ), static_cast<void const*>( &u ) );
}
int main()
{
using namespace boost::system;
test( result<int>::in_place_value, result<int>::in_place_error );
test( result<void>::in_place_value, result<void>::in_place_error );
test( result<int&>::in_place_value, result<int&>::in_place_error );
return boost::report_errors();
}

View File

@@ -508,6 +508,8 @@ int main()
BOOST_TEST_EQ( Y::instances, 0 );
//
{
result<void> r;
result<void> r2;
@@ -600,5 +602,110 @@ int main()
BOOST_TEST_EQ( r2.error(), ec );
}
//
{
int x1 = 1;
int x2 = 2;
result<int&> r1( x1 );
result<int&> r2( x2 );
r2 = std::move( r1 );
BOOST_TEST_EQ( x1, 1 );
BOOST_TEST_EQ( x2, 2 );
BOOST_TEST( r2.has_value() );
BOOST_TEST( !r2.has_error() );
BOOST_TEST_EQ( r2.value(), 1 );
BOOST_TEST_EQ( r1, r2 );
BOOST_TEST_EQ( &*r1, &*r2 );
}
{
int x1 = 1;
result<int&> r1( x1 );
result<int&> r2( ENOENT, generic_category() );
r2 = std::move( r1 );
BOOST_TEST_EQ( x1, 1 );
BOOST_TEST( r2.has_value() );
BOOST_TEST( !r2.has_error() );
BOOST_TEST_EQ( r2.value(), 1 );
BOOST_TEST_EQ( r1, r2 );
}
{
int x1 = 1;
auto ec = make_error_code( errc::invalid_argument );
result<int&> r1( ec );
result<int&> r2( x1 );
r2 = std::move( r1 );
BOOST_TEST_EQ( x1, 1 );
BOOST_TEST( !r2.has_value() );
BOOST_TEST( r2.has_error() );
BOOST_TEST_EQ( r2.error(), ec );
}
{
int x1 = 1;
auto ec = make_error_code( errc::invalid_argument );
result<int&> r2( x1 );
r2 = result<int&>( ec );
BOOST_TEST_EQ( x1, 1 );
BOOST_TEST( !r2.has_value() );
BOOST_TEST( r2.has_error() );
BOOST_TEST_EQ( r2.error(), ec );
}
{
auto ec = make_error_code( errc::invalid_argument );
result<int&> r1( ec );
result<int&> r2( ENOENT, generic_category() );
r2 = std::move( r1 );
BOOST_TEST( !r2.has_value() );
BOOST_TEST( r2.has_error() );
BOOST_TEST_EQ( r2.error(), ec );
}
{
auto ec = make_error_code( errc::invalid_argument );
result<int&> r2( ENOENT, generic_category() );
r2 = result<int&>( ec );
BOOST_TEST( !r2.has_value() );
BOOST_TEST( r2.has_error() );
BOOST_TEST_EQ( r2.error(), ec );
}
//
return boost::report_errors();
}

View File

@@ -207,6 +207,8 @@ int main()
BOOST_TEST_EQ( X::instances, 0 );
//
{
result<void> r;
result<void> r2( std::move( r ) );
@@ -245,5 +247,149 @@ int main()
BOOST_TEST_EQ( r2.error(), ec );
}
//
{
int x1 = 1;
result<int&> r1( x1 );
result<int&> r2( std::move( r1 ) );
BOOST_TEST( r1.has_value() );
BOOST_TEST( !r1.has_error() );
BOOST_TEST_EQ( r1.value(), 1 );
BOOST_TEST_EQ( &*r1, &x1 );
BOOST_TEST( r2.has_value() );
BOOST_TEST( !r2.has_error() );
BOOST_TEST_EQ( r2.value(), 1 );
BOOST_TEST_EQ( &*r2, &x1 );
}
{
int const x1 = 1;
result<int const&> r1( x1 );
result<int const&> r2( std::move( r1 ) );
BOOST_TEST( r1.has_value() );
BOOST_TEST( !r1.has_error() );
BOOST_TEST_EQ( r1.value(), 1 );
BOOST_TEST_EQ( &*r1, &x1 );
BOOST_TEST( r2.has_value() );
BOOST_TEST( !r2.has_error() );
BOOST_TEST_EQ( r2.value(), 1 );
BOOST_TEST_EQ( &*r2, &x1 );
}
{
int x1 = 1;
result<int&> r2(( result<int&>( x1 ) ));
BOOST_TEST( r2.has_value() );
BOOST_TEST( !r2.has_error() );
BOOST_TEST_EQ( r2.value(), 1 );
BOOST_TEST_EQ( &*r2, &x1 );
}
{
int const x1 = 1;
result<int const&> r2(( result<int const&>( x1 ) ));
BOOST_TEST( r2.has_value() );
BOOST_TEST( !r2.has_error() );
BOOST_TEST_EQ( r2.value(), 1 );
BOOST_TEST_EQ( &*r2, &x1 );
}
{
X x1( 1 );
result<X&> r1( x1 );
result<X&> r2( std::move( r1 ) );
BOOST_TEST( r1.has_value() );
BOOST_TEST( !r1.has_error() );
BOOST_TEST_EQ( r1.value().v_, 1 );
BOOST_TEST_EQ( &*r1, &x1 );
BOOST_TEST( r2.has_value() );
BOOST_TEST( !r2.has_error() );
BOOST_TEST_EQ( r2.value().v_, 1 );
BOOST_TEST_EQ( &*r2, &x1 );
BOOST_TEST_EQ( X::instances, 1 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
X x1( 1 );
result<X&> r2(( result<X&>( x1 ) ));
BOOST_TEST( r2.has_value() );
BOOST_TEST( !r2.has_error() );
BOOST_TEST_EQ( r2.value().v_, 1 );
BOOST_TEST_EQ( &*r2, &x1 );
BOOST_TEST_EQ( X::instances, 1 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
X const x1( 1 );
result<X const&> r1( x1 );
result<X const&> r2( std::move( r1 ) );
BOOST_TEST( r1.has_value() );
BOOST_TEST( !r1.has_error() );
BOOST_TEST_EQ( r1.value().v_, 1 );
BOOST_TEST_EQ( &*r1, &x1 );
BOOST_TEST( r2.has_value() );
BOOST_TEST( !r2.has_error() );
BOOST_TEST_EQ( r2.value().v_, 1 );
BOOST_TEST_EQ( &*r2, &x1 );
BOOST_TEST_EQ( X::instances, 1 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
X const x1( 1 );
result<X const&> r2(( result<X const&>( x1 ) ));
BOOST_TEST( r2.has_value() );
BOOST_TEST( !r2.has_error() );
BOOST_TEST_EQ( r2.value().v_, 1 );
BOOST_TEST_EQ( &*r2, &x1 );
BOOST_TEST_EQ( X::instances, 1 );
}
BOOST_TEST_EQ( X::instances, 0 );
//
return boost::report_errors();
}

359
test/result_or_fn0r.cpp Normal file
View File

@@ -0,0 +1,359 @@
// Copyright 2017, 2021, 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/system/result.hpp>
#include <boost/core/lightweight_test.hpp>
using namespace boost::system;
struct X
{
int v_;
};
struct Y
{
int v_;
explicit Y( int v ): v_( v ) {}
Y( X x ): v_( x.v_) {}
Y( Y const& ) = delete;
Y& operator=( Y const& ) = delete;
Y( Y&& r ): v_( r.v_ )
{
r.v_ = 0;
}
Y& operator=( Y&& ) = delete;
};
struct E
{
};
result<int, E> fi()
{
return 2;
}
result<int, E> fi2()
{
return E();
}
result<Y, E> fy()
{
return Y{ 2 };
}
result<Y, E> fy2()
{
return E();
}
result<int&, E> fri()
{
static int x = 2;
return x;
}
result<int&, E> fri2()
{
return E();
}
result<void, E> fv()
{
return {};
}
result<void, E> fv2()
{
return E();
}
int main()
{
{
result<int> r( 1 );
int x = r | fi | 3;
BOOST_TEST_EQ( x, 1 );
}
{
result<int> const r( 1 );
int x = r | fi | 3;
BOOST_TEST_EQ( x, 1 );
}
{
int x = result<int>( 1 ) | fi | 3;
BOOST_TEST_EQ( x, 1 );
}
{
result<int> r( 1 );
int x = r | fi2 | 3;
BOOST_TEST_EQ( x, 1 );
}
{
result<int> const r( 1 );
int x = r | fi2 | 3;
BOOST_TEST_EQ( x, 1 );
}
{
int x = result<int>( 1 ) | fi2 | 3;
BOOST_TEST_EQ( x, 1 );
}
{
result<int> r( in_place_error );
int x = r | fi | 3;
BOOST_TEST_EQ( x, 2 );
}
{
result<int> const r( in_place_error );
int x = r | fi | 3;
BOOST_TEST_EQ( x, 2 );
}
{
int x = result<int>( in_place_error ) | fi | 3;
BOOST_TEST_EQ( x, 2 );
}
{
result<int> r( in_place_error );
int x = r | fi2 | 3;
BOOST_TEST_EQ( x, 3 );
}
{
result<int> const r( in_place_error );
int x = r | fi2 | 3;
BOOST_TEST_EQ( x, 3 );
}
{
int x = result<int>( in_place_error ) | fi2 | 3;
BOOST_TEST_EQ( x, 3 );
}
{
Y y = result<X>( X{1} ) | fy | X{3};
BOOST_TEST_EQ( y.v_, 1 );
}
{
Y y = result<X>( X{1} ) | fy2 | X{3};
BOOST_TEST_EQ( y.v_, 1 );
}
{
Y y = result<X, E>( in_place_error ) | fy | X{3};
BOOST_TEST_EQ( y.v_, 2 );
}
{
Y y = result<X, E>( in_place_error ) | fy2 | Y{3};
BOOST_TEST_EQ( y.v_, 3 );
}
{
int x1 = 1;
int x3 = 3;
result<int&> r( x1 );
int& x = r | fri | x3;
BOOST_TEST_EQ( &x, &x1 );
}
{
int x1 = 1;
int x3 = 3;
result<int&> const r( x1 );
int& x = r | fri | x3;
BOOST_TEST_EQ( &x, &x1 );
}
{
int x1 = 1;
int x3 = 3;
int& x = result<int&>( x1 ) | fri | x3;
BOOST_TEST_EQ( &x, &x1 );
}
{
int x1 = 1;
int x3 = 3;
result<int&> r( x1 );
int& x = r | fri2 | x3;
BOOST_TEST_EQ( &x, &x1 );
}
{
int x1 = 1;
int x3 = 3;
result<int&> const r( x1 );
int& x = r | fri2 | x3;
BOOST_TEST_EQ( &x, &x1 );
}
{
int x1 = 1;
int x3 = 3;
int& x = result<int&>( x1 ) | fri2 | x3;
BOOST_TEST_EQ( &x, &x1 );
}
{
int x3 = 3;
result<int&, E> r( in_place_error );
int& x = r | fri | x3;
BOOST_TEST_EQ( &x, &*fri() );
}
{
int x3 = 3;
result<int&, E> const r( in_place_error );
int& x = r | fri | x3;
BOOST_TEST_EQ( &x, &*fri() );
}
{
int x3 = 3;
int& x = result<int&, E>( in_place_error ) | fri | x3;
BOOST_TEST_EQ( &x, &*fri() );
}
{
int x3 = 3;
result<int&, E> r( in_place_error );
int& x = r | fri2 | x3;
BOOST_TEST_EQ( &x, &x3 );
}
{
int x3 = 3;
result<int&, E> const r( in_place_error );
int& x = r | fri2 | x3;
BOOST_TEST_EQ( &x, &x3 );
}
{
int x3 = 3;
int& x = result<int&, E>( in_place_error ) | fri2 | x3;
BOOST_TEST_EQ( &x, &x3 );
}
{
result<void> r;
result<void, E> r2 = r | fv;
BOOST_TEST( r2.has_value() );
}
{
result<void> r;
result<void, E> r2 = r | fv2;
BOOST_TEST( r2.has_value() );
}
{
result<void> r( in_place_error );
result<void, E> r2 = r | fv;
BOOST_TEST( r2.has_value() );
}
{
result<void> r( in_place_error );
result<void, E> r2 = r | fv2;
BOOST_TEST( r2.has_error() );
}
{
result<void, E> r2 = result<void>() | fv;
BOOST_TEST( r2.has_value() );
}
{
result<void, E> r2 = result<void>() | fv2;
BOOST_TEST( r2.has_value() );
}
{
result<void, E> r2 = result<void>( in_place_error ) | fv;
BOOST_TEST( r2.has_value() );
}
{
result<void, E> r2 = result<void>( in_place_error ) | fv2;
BOOST_TEST( r2.has_error() );
}
return boost::report_errors();
}

162
test/result_or_fn0v.cpp Normal file
View File

@@ -0,0 +1,162 @@
// Copyright 2017, 2021, 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/system/result.hpp>
#include <boost/core/lightweight_test.hpp>
using namespace boost::system;
struct X
{
int v_;
};
struct Y
{
int v_;
explicit Y( int v ): v_( v ) {}
Y( X x ): v_( x.v_) {}
Y( Y const& ) = delete;
Y& operator=( Y const& ) = delete;
Y( Y&& r ): v_( r.v_ )
{
r.v_ = 0;
}
Y& operator=( Y&& ) = delete;
};
struct E
{
};
int f()
{
return 2;
}
X g()
{
return { 2 };
}
int& h()
{
static int x = 2;
return x;
}
int main()
{
{
result<int> r( 1 );
int x = r | f;
BOOST_TEST_EQ( x, 1 );
}
{
result<int> const r( 1 );
int x = r | f;
BOOST_TEST_EQ( x, 1 );
}
{
int x = result<int>( 1 ) | f;
BOOST_TEST_EQ( x, 1 );
}
{
result<int, E> r( in_place_error );
int x = r | f;
BOOST_TEST_EQ( x, 2 );
}
{
result<int, E> const r( in_place_error );
int x = r | f;
BOOST_TEST_EQ( x, 2 );
}
{
int x = result<int, E>( in_place_error ) | f;
BOOST_TEST_EQ( x, 2 );
}
{
Y y = result<Y>( in_place_value, 1 ) | g;
BOOST_TEST_EQ( y.v_, 1 );
}
{
Y y = result<Y, E>( in_place_error ) | g;
BOOST_TEST_EQ( y.v_, 2 );
}
{
int x1 = 1;
result<int&> r( x1 );
int& x = r | h;
BOOST_TEST_EQ( &x, &x1 );
}
{
int x1 = 1;
result<int&> const r( x1 );
int& x = r | h;
BOOST_TEST_EQ( &x, &x1 );
}
{
int x1 = 1;
int& x = result<int&>( x1 ) | h;
BOOST_TEST_EQ( &x, &x1 );
}
{
result<int&, E> r( in_place_error );
int& x = r | h;
BOOST_TEST_EQ( &x, &h() );
}
{
result<int&, E> const r( in_place_error );
int& x = r | h;
BOOST_TEST_EQ( &x, &h() );
}
{
int& x = result<int&, E>( in_place_error ) | h;
BOOST_TEST_EQ( &x, &h() );
}
return boost::report_errors();
}

167
test/result_or_value.cpp Normal file
View File

@@ -0,0 +1,167 @@
// Copyright 2017, 2021, 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/system/result.hpp>
#include <boost/core/lightweight_test.hpp>
using namespace boost::system;
struct X
{
int v_;
};
struct Y
{
int v_;
explicit Y( int v ): v_( v ) {}
Y( X x ): v_( x.v_) {}
Y( Y const& ) = delete;
Y& operator=( Y const& ) = delete;
Y( Y&& r ): v_( r.v_ )
{
r.v_ = 0;
}
Y& operator=( Y&& ) = delete;
};
struct E
{
};
int main()
{
{
result<int> r( 1 );
int x = r | 2;
BOOST_TEST_EQ( x, 1 );
}
{
result<int> const r( 1 );
int x = r | 2;
BOOST_TEST_EQ( x, 1 );
}
{
int x = result<int>( 1 ) | 2;
BOOST_TEST_EQ( x, 1 );
}
{
result<int, E> r( in_place_error );
int x = r | 2;
BOOST_TEST_EQ( x, 2 );
}
{
result<int, E> const r( in_place_error );
int x = r | 2;
BOOST_TEST_EQ( x, 2 );
}
{
int x = result<int, E>( in_place_error ) | 2;
BOOST_TEST_EQ( x, 2 );
}
{
Y y = result<Y>( in_place_value, 1 ) | Y{2};
BOOST_TEST_EQ( y.v_, 1 );
}
{
Y y = result<Y, E>( in_place_error ) | Y{2};
BOOST_TEST_EQ( y.v_, 2 );
}
{
Y y = result<Y>( in_place_value, 1 ) | X{2};
BOOST_TEST_EQ( y.v_, 1 );
}
{
Y y = result<Y, E>( in_place_error ) | X{2};
BOOST_TEST_EQ( y.v_, 2 );
}
{
int x1 = 1;
int x2 = 2;
result<int&> r( x1 );
int& x = r | x2;
BOOST_TEST_EQ( &x, &x1 );
}
{
int x1 = 1;
int x2 = 2;
result<int&> const r( x1 );
int& x = r | x2;
BOOST_TEST_EQ( &x, &x1 );
}
{
int x1 = 1;
int x2 = 2;
int& x = result<int&>( x1 ) | x2;
BOOST_TEST_EQ( &x, &x1 );
}
{
int x2 = 2;
result<int&, E> r( in_place_error );
int& x = r | x2;
BOOST_TEST_EQ( &x, &x2 );
}
{
int x2 = 2;
result<int&, E> const r( in_place_error );
int& x = r | x2;
BOOST_TEST_EQ( &x, &x2 );
}
{
int x2 = 2;
int& x = result<int&, E>( in_place_error ) | x2;
BOOST_TEST_EQ( &x, &x2 );
}
return boost::report_errors();
}

View File

@@ -0,0 +1,14 @@
// Copyright 2017, 2021, 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/system/result.hpp>
using namespace boost::system;
int main()
{
int x = 1;
result<int const&> r( x );
r | 2;
}

View File

@@ -0,0 +1,13 @@
// Copyright 2017, 2021, 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/system/result.hpp>
using namespace boost::system;
int main()
{
int x = 1;
result<int const&>( x ) | 2;
}

View File

@@ -259,5 +259,55 @@ int main()
BOOST_TEST_EQ( r2, r2c );
}
{
int x1 = 1;
int x2 = 2;
result<int&> r1( x1 ), r1c( r1 );
result<int&> r2( x2 ), r2c( r2 );
r1.swap( r2 );
BOOST_TEST_EQ( r1, r2c );
BOOST_TEST_EQ( r2, r1c );
swap( r1, r2 );
BOOST_TEST_EQ( r1, r1c );
BOOST_TEST_EQ( r2, r2c );
}
{
result<int&> r1( 1, generic_category() ), r1c( r1 );
result<int&> r2( 2, generic_category() ), r2c( r2 );
r1.swap( r2 );
BOOST_TEST_EQ( r1, r2c );
BOOST_TEST_EQ( r2, r1c );
swap( r1, r2 );
BOOST_TEST_EQ( r1, r1c );
BOOST_TEST_EQ( r2, r2c );
}
{
int x1 = 1;
result<int&> r1( x1 ), r1c( r1 );
result<int&> r2( 2, generic_category() ), r2c( r2 );
r1.swap( r2 );
BOOST_TEST_EQ( r1, r2c );
BOOST_TEST_EQ( r2, r1c );
swap( r1, r2 );
BOOST_TEST_EQ( r1, r1c );
BOOST_TEST_EQ( r2, r2c );
}
return boost::report_errors();
}

View File

@@ -12,11 +12,28 @@ struct X {};
int main()
{
BOOST_TEST_TRAIT_SAME( result<int>::value_type, int );
BOOST_TEST_TRAIT_SAME( result<X>::value_type, X );
BOOST_TEST_TRAIT_SAME( result<void>::value_type, void );
BOOST_TEST_TRAIT_SAME( result<int>::error_type, error_code );
BOOST_TEST_TRAIT_SAME( result<X>::value_type, X );
BOOST_TEST_TRAIT_SAME( result<X>::error_type, error_code );
BOOST_TEST_TRAIT_SAME( result<void>::value_type, void );
BOOST_TEST_TRAIT_SAME( result<void>::error_type, error_code );
BOOST_TEST_TRAIT_SAME( result<int&>::value_type, int& );
BOOST_TEST_TRAIT_SAME( result<int&>::error_type, error_code );
BOOST_TEST_TRAIT_SAME( result<int, X>::value_type, int );
BOOST_TEST_TRAIT_SAME( result<int, X>::error_type, X );
BOOST_TEST_TRAIT_SAME( result<X, X>::value_type, X );
BOOST_TEST_TRAIT_SAME( result<X, X>::error_type, X );
BOOST_TEST_TRAIT_SAME( result<void, X>::value_type, void );
BOOST_TEST_TRAIT_SAME( result<void, X>::error_type, X );
BOOST_TEST_TRAIT_SAME( result<int&, X>::value_type, int& );
BOOST_TEST_TRAIT_SAME( result<int&, X>::error_type, X );
return boost::report_errors();
}

View File

@@ -336,6 +336,8 @@ int main()
BOOST_TEST_EQ( (result<X, Y>( ec ).operator->()), static_cast<X*>(0) );
}
//
{
result<void> r;
@@ -497,5 +499,179 @@ int main()
BOOST_TEST_EQ( r.operator->(), static_cast<void*>(0) );
}
//
{
int x1 = 1;
result<int&> r( x1 );
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST( r );
BOOST_TEST_NOT( !r );
BOOST_TEST_EQ( r.value(), 1 );
BOOST_TEST_EQ( *r, 1 );
BOOST_TEST_EQ( r.operator->(), &*r );
}
{
int x1 = 1;
result<int&> const r( x1 );
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST( r );
BOOST_TEST_NOT( !r );
BOOST_TEST_EQ( r.value(), 1 );
BOOST_TEST_EQ( *r, 1 );
BOOST_TEST_EQ( r.operator->(), &*r );
}
{
int x1 = 1;
BOOST_TEST( result<int&>( x1 ).has_value() );
BOOST_TEST( !result<int&>( x1 ).has_error() );
BOOST_TEST( result<int&>( x1 ) );
BOOST_TEST_NOT( !result<int&>( x1 ) );
BOOST_TEST_EQ( result<int&>( x1 ).value(), 1 );
BOOST_TEST_EQ( *result<int&>( x1 ), 1 );
BOOST_TEST_EQ( result<int&>( x1 ).operator->(), &x1 );
}
{
auto ec = make_error_code( errc::invalid_argument );
result<int&> r( ec );
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_NOT( r );
BOOST_TEST( !r );
BOOST_TEST_THROWS( r.value(), system_error );
BOOST_TEST_EQ( r.operator->(), static_cast<int*>(0) );
}
{
auto ec = make_error_code( errc::invalid_argument );
result<int&> const r( ec );
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_NOT( r );
BOOST_TEST( !r );
BOOST_TEST_THROWS( r.value(), system_error );
BOOST_TEST_EQ( r.operator->(), static_cast<int*>(0) );
}
{
auto ec = make_error_code( errc::invalid_argument );
BOOST_TEST( !result<int&>( ec ).has_value() );
BOOST_TEST( result<int&>( ec ).has_error() );
BOOST_TEST_NOT( result<int&>( ec ) );
BOOST_TEST( !result<int&>( ec ) );
BOOST_TEST_THROWS( result<int&>( ec ).value(), system_error );
BOOST_TEST_EQ( result<int&>( ec ).operator->(), static_cast<int*>(0) );
}
{
auto ec = make_error_code( std::errc::invalid_argument );
result<int&, std::error_code> const r( ec );
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_NOT( r );
BOOST_TEST( !r );
BOOST_TEST_THROWS( r.value(), std::system_error );
BOOST_TEST_EQ( r.operator->(), static_cast<int*>(0) );
}
{
result<int&, errc::errc_t> const r( in_place_error, errc::invalid_argument );
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_NOT( r );
BOOST_TEST( !r );
BOOST_TEST_THROWS( r.value(), system_error );
BOOST_TEST_EQ( r.operator->(), static_cast<int*>(0) );
}
{
result<int&, std::errc> const r( std::errc::invalid_argument );
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_NOT( r );
BOOST_TEST( !r );
BOOST_TEST_THROWS( r.value(), std::system_error );
BOOST_TEST_EQ( r.operator->(), static_cast<int*>(0) );
}
{
result<int&, std::exception_ptr> const r( std::make_exception_ptr( E2() ) );
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_NOT( r );
BOOST_TEST( !r );
#if defined(BOOST_CLANG_VERSION) && BOOST_CLANG_VERSION < 30600
#else
BOOST_TEST_THROWS( r.value(), E2 );
#endif
BOOST_TEST_EQ( r.operator->(), static_cast<int*>(0) );
}
{
result<int&, std::exception_ptr> const r( in_place_error );
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_NOT( r );
BOOST_TEST( !r );
BOOST_TEST_THROWS( r.value(), std::bad_exception );
BOOST_TEST_EQ( r.operator->(), static_cast<int*>(0) );
}
//
return boost::report_errors();
}

View File

@@ -69,6 +69,11 @@ result<std::vector<int>> fv2()
return {{ 1, 2 }};
}
result<void> fw0()
{
return {};
}
int main()
{
{
@@ -148,5 +153,12 @@ int main()
BOOST_TEST_EQ( r->at(1), 2 );
}
{
result<void> r = fw0();
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
}
return boost::report_errors();
}

View File

@@ -114,5 +114,29 @@ int main()
BOOST_TEST( !r.has_error() );
}
{
int x1 = 1;
using R = result<int&>;
R r( R::in_place_value, x1 );
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST_EQ( r.value(), 1 );
}
{
int x1 = 1;
using R = result<int&, int>;
R r( R::in_place_value, x1 );
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST_EQ( *r, 1 );
}
return boost::report_errors();
}

View File

@@ -0,0 +1,121 @@
// Copyright 2017, 2021, 2023 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/system/result.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>
using namespace boost::system;
struct X
{
static int instances;
int v_;
explicit X( int v ): v_( v ) { ++instances; }
X( X const& ) = delete;
X& operator=( X const& ) = delete;
~X() { --instances; }
};
int X::instances = 0;
int main()
{
{
int x = 0;
result<int&> r( x );
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST_EQ( r.value(), 0 );
}
{
int x = 0;
result<int&> r = x;
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST_EQ( r.value(), 0 );
}
{
int x = 1;
result<int&, int> r( in_place_value, x );
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST_EQ( *r, 1 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
X x( 1 );
result<X&> r( x );
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST_EQ( r.value().v_, 1 );
BOOST_TEST_EQ( X::instances, 1 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
X x( 1 );
result<X&> r = x;
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST_EQ( r.value().v_, 1 );
BOOST_TEST_EQ( X::instances, 1 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
X x( 1 );
result<X&, X> r( in_place_value, x );
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST_EQ( r->v_, 1 );
BOOST_TEST_EQ( X::instances, 1 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
BOOST_TEST_TRAIT_TRUE((std::is_constructible<result<int&>, int&>));
BOOST_TEST_TRAIT_TRUE((std::is_convertible<int&, result<int&>>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<int&>, int const&>));
BOOST_TEST_TRAIT_FALSE((std::is_convertible<int const&, result<int&>>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<int&>, int>));
BOOST_TEST_TRAIT_FALSE((std::is_convertible<int, result<int&>>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<int&, int>, int&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<int&, float>, int&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<X&>, int>));
BOOST_TEST_TRAIT_FALSE((std::is_convertible<int, result<X&>>));
}
return boost::report_errors();
}

View File

@@ -0,0 +1,211 @@
// Copyright 2017, 2021, 2023 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/system/result.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>
using namespace boost::system;
struct X
{
static int instances;
int v_;
explicit X( int v ): v_( v ) { ++instances; }
X( X const& ) = delete;
X& operator=( X const& ) = delete;
~X() { --instances; }
};
int X::instances = 0;
int main()
{
{
int x = 0;
result<int const&> r( x );
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST_EQ( r.value(), 0 );
}
{
int const x = 0;
result<int const&> r( x );
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST_EQ( r.value(), 0 );
}
{
int x = 0;
result<int const&> r = x;
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST_EQ( r.value(), 0 );
}
{
int const x = 0;
result<int const&> r = x;
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST_EQ( r.value(), 0 );
}
{
int x = 1;
result<int const&, int> r( in_place_value, x );
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST_EQ( *r, 1 );
}
{
int const x = 1;
result<int const&, int> r( in_place_value, x );
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST_EQ( *r, 1 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
X x( 1 );
result<X const&> r( x );
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST_EQ( r.value().v_, 1 );
BOOST_TEST_EQ( X::instances, 1 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
X const x( 1 );
result<X const&> r( x );
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST_EQ( r.value().v_, 1 );
BOOST_TEST_EQ( X::instances, 1 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
X x( 1 );
result<X const&> r = x;
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST_EQ( r.value().v_, 1 );
BOOST_TEST_EQ( X::instances, 1 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
X const x( 1 );
result<X const&> r = x;
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST_EQ( r.value().v_, 1 );
BOOST_TEST_EQ( X::instances, 1 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
X x( 1 );
result<X const&, X> r( in_place_value, x );
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST_EQ( r->v_, 1 );
BOOST_TEST_EQ( X::instances, 1 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
X const x( 1 );
result<X const&, X> r( in_place_value, x );
BOOST_TEST( r.has_value() );
BOOST_TEST( !r.has_error() );
BOOST_TEST_EQ( r->v_, 1 );
BOOST_TEST_EQ( X::instances, 1 );
}
BOOST_TEST_EQ( X::instances, 0 );
{
BOOST_TEST_TRAIT_TRUE((std::is_constructible<result<int const&>, int&>));
BOOST_TEST_TRAIT_TRUE((std::is_convertible<int&, result<int const&>>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<result<int const&>, int const&>));
BOOST_TEST_TRAIT_TRUE((std::is_convertible<int const&, result<int const&>>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<int const&>, int>));
BOOST_TEST_TRAIT_FALSE((std::is_convertible<int, result<int const&>>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<double const&>, int&>));
BOOST_TEST_TRAIT_FALSE((std::is_convertible<int&, result<double const&>>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<double const&>, int const&>));
BOOST_TEST_TRAIT_FALSE((std::is_convertible<int const&, result<double const&>>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<double const&>, int>));
BOOST_TEST_TRAIT_FALSE((std::is_convertible<int, result<double const&>>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<int const&, int>, int&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<int const&, float>, int&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<int const&, int>, int const&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<int const&, float>, int const&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<int const&, int>, int>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<int const&, float>, int>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<X const&>, int>));
BOOST_TEST_TRAIT_FALSE((std::is_convertible<int, result<X const&>>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<X const&>, X const>));
BOOST_TEST_TRAIT_FALSE((std::is_convertible<X const, result<X const&>>));
}
return boost::report_errors();
}