forked from TartanLlama/expected
Do CMake properly
This commit is contained in:
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "cmake/tl-cmake"]
|
||||
path = cmake/tl-cmake
|
||||
url = https://github.com/TartanLlama/tl-cmake.git
|
@ -1,12 +1,14 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.8)
|
||||
|
||||
project(expected)
|
||||
project(tl-expected VERSION 1.0.0 LANGUAGES CXX)
|
||||
|
||||
option(EXPECTED_ENABLE_TESTS "Enable tests." ON)
|
||||
|
||||
add_library(expected INTERFACE)
|
||||
target_sources(expected INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/tl/expected.hpp)
|
||||
target_include_directories(expected INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/tl)
|
||||
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/tl-cmake" ${CMAKE_MODULE_PATH})
|
||||
include(add-tl)
|
||||
|
||||
tl_add_library(expected SOURCES
|
||||
include/tl/expected.hpp)
|
||||
|
||||
# Prepare "Catch" library for other executables
|
||||
set(CATCH_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/test)
|
||||
|
1
cmake/tl-cmake
Submodule
1
cmake/tl-cmake
Submodule
Submodule cmake/tl-cmake added at 284c6a3f0f
3
cmake/tl-expected-config.cmake.in
Normal file
3
cmake/tl-expected-config.cmake.in
Normal file
@ -0,0 +1,3 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/tl-expected-targets.cmake")
|
@ -12,8 +12,8 @@ class ExpectedConan(ConanFile):
|
||||
exports_sources = "*"
|
||||
|
||||
def source(self):
|
||||
tools.replace_in_file('CMakeLists.txt', 'project(expected)',
|
||||
'''project(expected)
|
||||
tools.replace_in_file('CMakeLists.txt', 'project(tl-expected)',
|
||||
'''project(tl-expected)
|
||||
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
|
||||
conan_basic_setup()
|
||||
''')
|
||||
@ -31,4 +31,4 @@ conan_basic_setup()
|
||||
self.run('%s/bin/tests' % self.build_folder)
|
||||
|
||||
def package(self):
|
||||
self.copy('*.hpp', dst='include/tl', src='tl')
|
||||
self.copy('*.hpp', dst='include/tl', src='include/tl')
|
BIN
include/tl/expected.hpp.gch
Normal file
BIN
include/tl/expected.hpp.gch
Normal file
Binary file not shown.
@ -1,5 +1,5 @@
|
||||
#include "catch.hpp"
|
||||
#include "expected.hpp"
|
||||
#include <tl/expected.hpp>
|
||||
|
||||
TEST_CASE("Simple assignment", "[assignment.simple]") {
|
||||
tl::expected<int, int> e1 = 42;
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "catch.hpp"
|
||||
#include "expected.hpp"
|
||||
#include <tl/expected.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "catch.hpp"
|
||||
#include "expected.hpp"
|
||||
#include <tl/expected.hpp>
|
||||
|
||||
TEST_CASE("Constexpr", "[constexpr]") {
|
||||
//TODO
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "catch.hpp"
|
||||
#include "expected.hpp"
|
||||
#include <tl/expected.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <type_traits>
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "catch.hpp"
|
||||
#include "expected.hpp"
|
||||
#include <tl/expected.hpp>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "catch.hpp"
|
||||
#include "expected.hpp"
|
||||
#include <tl/expected.hpp>
|
||||
|
||||
#define TOKENPASTE(x, y) x##y
|
||||
#define TOKENPASTE2(x, y) TOKENPASTE(x, y)
|
||||
|
256
tests/issues.cpp
256
tests/issues.cpp
@ -1,129 +1,129 @@
|
||||
#include "catch.hpp"
|
||||
#include "expected.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
using std::string;
|
||||
|
||||
tl::expected<int, string> getInt3(int val) { return val; }
|
||||
|
||||
tl::expected<int, string> getInt2(int val) { return val; }
|
||||
|
||||
tl::expected<int, string> getInt1() { return getInt2(5).and_then(getInt3); }
|
||||
|
||||
TEST_CASE("Issue 1", "[issues.1]") { getInt1(); }
|
||||
|
||||
tl::expected<int, int> operation1() { return 42; }
|
||||
|
||||
tl::expected<std::string, int> operation2(int const val) { return "Bananas"; }
|
||||
|
||||
TEST_CASE("Issue 17", "[issues.17]") {
|
||||
auto const intermediate_result = operation1();
|
||||
|
||||
intermediate_result.and_then(operation2);
|
||||
}
|
||||
|
||||
struct a {};
|
||||
struct b : a {};
|
||||
|
||||
auto doit() -> tl::expected<std::unique_ptr<b>, int> {
|
||||
return tl::make_unexpected(0);
|
||||
}
|
||||
|
||||
TEST_CASE("Issue 23", "[issues.23]") {
|
||||
tl::expected<std::unique_ptr<a>, int> msg = doit();
|
||||
REQUIRE(!msg.has_value());
|
||||
}
|
||||
|
||||
TEST_CASE("Issue 26", "[issues.26]") {
|
||||
tl::expected<a, int> exp = tl::expected<b, int>(tl::unexpect, 0);
|
||||
REQUIRE(!exp.has_value());
|
||||
}
|
||||
|
||||
struct foo {
|
||||
foo() = default;
|
||||
foo(foo &) = delete;
|
||||
foo(foo &&){};
|
||||
};
|
||||
|
||||
TEST_CASE("Issue 29", "[issues.29]") {
|
||||
std::vector<foo> v;
|
||||
v.emplace_back();
|
||||
tl::expected<std::vector<foo>, int> ov = std::move(v);
|
||||
REQUIRE(ov->size() == 1);
|
||||
}
|
||||
|
||||
tl::expected<int, std::string> error() {
|
||||
return tl::make_unexpected(std::string("error1 "));
|
||||
}
|
||||
std::string maperror(std::string s) { return s + "maperror "; }
|
||||
|
||||
TEST_CASE("Issue 30", "[issues.30]") {
|
||||
error().map_error(maperror);
|
||||
}
|
||||
|
||||
struct i31{
|
||||
int i;
|
||||
};
|
||||
TEST_CASE("Issue 31", "[issues.31]") {
|
||||
const tl::expected<i31, int> a = i31{42};
|
||||
a->i;
|
||||
|
||||
tl::expected< void, std::string > result;
|
||||
tl::expected< void, std::string > result2 = result;
|
||||
result2 = result;
|
||||
}
|
||||
|
||||
TEST_CASE("Issue 33", "[issues.33]") {
|
||||
tl::expected<void, int> res {tl::unexpect, 0};
|
||||
REQUIRE(!res);
|
||||
res = res.map_error([](int i) { return 42; });
|
||||
REQUIRE(res.error() == 42);
|
||||
}
|
||||
|
||||
|
||||
tl::expected<void, std::string> voidWork() { return {}; }
|
||||
tl::expected<int, std::string> work2() { return 42; }
|
||||
void errorhandling(std::string){}
|
||||
|
||||
TEST_CASE("Issue 34", "[issues.34]") {
|
||||
tl::expected <int, std::string> result = voidWork ()
|
||||
.and_then (work2);
|
||||
result.map_error ([&] (std::string result) {errorhandling (result);});
|
||||
}
|
||||
|
||||
struct non_copyable {
|
||||
non_copyable(non_copyable&&) = default;
|
||||
non_copyable(non_copyable const&) = delete;
|
||||
non_copyable() = default;
|
||||
};
|
||||
|
||||
TEST_CASE("Issue 42", "[issues.42]") {
|
||||
tl::expected<non_copyable,int>{}.map([](non_copyable) {});
|
||||
}
|
||||
|
||||
TEST_CASE("Issue 43", "[issues.43]") {
|
||||
auto result = tl::expected<void, std::string>{};
|
||||
result = tl::make_unexpected(std::string{ "foo" });
|
||||
}
|
||||
|
||||
#if !(__GNUC__ <= 5)
|
||||
#include <memory>
|
||||
|
||||
using MaybeDataPtr = tl::expected<int, std::unique_ptr<int>>;
|
||||
|
||||
MaybeDataPtr test(int i) noexcept
|
||||
{
|
||||
return std::move(i);
|
||||
}
|
||||
|
||||
MaybeDataPtr test2(int i) noexcept
|
||||
{
|
||||
return std::move(i);
|
||||
}
|
||||
|
||||
TEST_CASE("Issue 49", "[issues.49]") {
|
||||
auto m = test(10)
|
||||
.and_then(test2);
|
||||
}
|
||||
#include "catch.hpp"
|
||||
#include <tl/expected.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
using std::string;
|
||||
|
||||
tl::expected<int, string> getInt3(int val) { return val; }
|
||||
|
||||
tl::expected<int, string> getInt2(int val) { return val; }
|
||||
|
||||
tl::expected<int, string> getInt1() { return getInt2(5).and_then(getInt3); }
|
||||
|
||||
TEST_CASE("Issue 1", "[issues.1]") { getInt1(); }
|
||||
|
||||
tl::expected<int, int> operation1() { return 42; }
|
||||
|
||||
tl::expected<std::string, int> operation2(int const val) { return "Bananas"; }
|
||||
|
||||
TEST_CASE("Issue 17", "[issues.17]") {
|
||||
auto const intermediate_result = operation1();
|
||||
|
||||
intermediate_result.and_then(operation2);
|
||||
}
|
||||
|
||||
struct a {};
|
||||
struct b : a {};
|
||||
|
||||
auto doit() -> tl::expected<std::unique_ptr<b>, int> {
|
||||
return tl::make_unexpected(0);
|
||||
}
|
||||
|
||||
TEST_CASE("Issue 23", "[issues.23]") {
|
||||
tl::expected<std::unique_ptr<a>, int> msg = doit();
|
||||
REQUIRE(!msg.has_value());
|
||||
}
|
||||
|
||||
TEST_CASE("Issue 26", "[issues.26]") {
|
||||
tl::expected<a, int> exp = tl::expected<b, int>(tl::unexpect, 0);
|
||||
REQUIRE(!exp.has_value());
|
||||
}
|
||||
|
||||
struct foo {
|
||||
foo() = default;
|
||||
foo(foo &) = delete;
|
||||
foo(foo &&){};
|
||||
};
|
||||
|
||||
TEST_CASE("Issue 29", "[issues.29]") {
|
||||
std::vector<foo> v;
|
||||
v.emplace_back();
|
||||
tl::expected<std::vector<foo>, int> ov = std::move(v);
|
||||
REQUIRE(ov->size() == 1);
|
||||
}
|
||||
|
||||
tl::expected<int, std::string> error() {
|
||||
return tl::make_unexpected(std::string("error1 "));
|
||||
}
|
||||
std::string maperror(std::string s) { return s + "maperror "; }
|
||||
|
||||
TEST_CASE("Issue 30", "[issues.30]") {
|
||||
error().map_error(maperror);
|
||||
}
|
||||
|
||||
struct i31{
|
||||
int i;
|
||||
};
|
||||
TEST_CASE("Issue 31", "[issues.31]") {
|
||||
const tl::expected<i31, int> a = i31{42};
|
||||
a->i;
|
||||
|
||||
tl::expected< void, std::string > result;
|
||||
tl::expected< void, std::string > result2 = result;
|
||||
result2 = result;
|
||||
}
|
||||
|
||||
TEST_CASE("Issue 33", "[issues.33]") {
|
||||
tl::expected<void, int> res {tl::unexpect, 0};
|
||||
REQUIRE(!res);
|
||||
res = res.map_error([](int i) { return 42; });
|
||||
REQUIRE(res.error() == 42);
|
||||
}
|
||||
|
||||
|
||||
tl::expected<void, std::string> voidWork() { return {}; }
|
||||
tl::expected<int, std::string> work2() { return 42; }
|
||||
void errorhandling(std::string){}
|
||||
|
||||
TEST_CASE("Issue 34", "[issues.34]") {
|
||||
tl::expected <int, std::string> result = voidWork ()
|
||||
.and_then (work2);
|
||||
result.map_error ([&] (std::string result) {errorhandling (result);});
|
||||
}
|
||||
|
||||
struct non_copyable {
|
||||
non_copyable(non_copyable&&) = default;
|
||||
non_copyable(non_copyable const&) = delete;
|
||||
non_copyable() = default;
|
||||
};
|
||||
|
||||
TEST_CASE("Issue 42", "[issues.42]") {
|
||||
tl::expected<non_copyable,int>{}.map([](non_copyable) {});
|
||||
}
|
||||
|
||||
TEST_CASE("Issue 43", "[issues.43]") {
|
||||
auto result = tl::expected<void, std::string>{};
|
||||
result = tl::make_unexpected(std::string{ "foo" });
|
||||
}
|
||||
|
||||
#if !(__GNUC__ <= 5)
|
||||
#include <memory>
|
||||
|
||||
using MaybeDataPtr = tl::expected<int, std::unique_ptr<int>>;
|
||||
|
||||
MaybeDataPtr test(int i) noexcept
|
||||
{
|
||||
return std::move(i);
|
||||
}
|
||||
|
||||
MaybeDataPtr test2(int i) noexcept
|
||||
{
|
||||
return std::move(i);
|
||||
}
|
||||
|
||||
TEST_CASE("Issue 49", "[issues.49]") {
|
||||
auto m = test(10)
|
||||
.and_then(test2);
|
||||
}
|
||||
#endif
|
@ -1,5 +1,5 @@
|
||||
#include "catch.hpp"
|
||||
#include "expected.hpp"
|
||||
#include <tl/expected.hpp>
|
||||
|
||||
TEST_CASE("Noexcept", "[noexcept]") {
|
||||
//TODO
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "catch.hpp"
|
||||
#include "expected.hpp"
|
||||
#include <tl/expected.hpp>
|
||||
|
||||
struct move_detector {
|
||||
move_detector() = default;
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "catch.hpp"
|
||||
#include "expected.hpp"
|
||||
#include <tl/expected.hpp>
|
||||
|
||||
TEST_CASE("Relational operators", "[relops]") {
|
||||
//TODO
|
||||
|
200
tests/swap.cpp
200
tests/swap.cpp
@ -1,101 +1,101 @@
|
||||
#include "catch.hpp"
|
||||
#include "expected.hpp"
|
||||
|
||||
struct no_throw {
|
||||
no_throw(std::string i) : i(i) {}
|
||||
std::string i;
|
||||
};
|
||||
struct canthrow_move {
|
||||
canthrow_move(std::string i) : i(i) {}
|
||||
canthrow_move(canthrow_move const &) = default;
|
||||
canthrow_move(canthrow_move &&other) noexcept(false) : i(other.i) {}
|
||||
canthrow_move &operator=(canthrow_move &&) = default;
|
||||
std::string i;
|
||||
};
|
||||
|
||||
bool should_throw = false;
|
||||
struct willthrow_move {
|
||||
willthrow_move(std::string i) : i(i) {}
|
||||
willthrow_move(willthrow_move const &) = default;
|
||||
willthrow_move(willthrow_move &&other) : i(other.i) {
|
||||
if (should_throw)
|
||||
throw 0;
|
||||
}
|
||||
willthrow_move &operator=(willthrow_move &&) = default;
|
||||
std::string i;
|
||||
};
|
||||
static_assert(tl::detail::is_swappable<no_throw>::value, "");
|
||||
|
||||
template <class T1, class T2> void swap_test() {
|
||||
std::string s1 = "abcdefghijklmnopqrstuvwxyz";
|
||||
std::string s2 = "zyxwvutsrqponmlkjihgfedcba";
|
||||
|
||||
tl::expected<T1, T2> a{s1};
|
||||
tl::expected<T1, T2> b{s2};
|
||||
swap(a, b);
|
||||
REQUIRE(a->i == s2);
|
||||
REQUIRE(b->i == s1);
|
||||
|
||||
a = s1;
|
||||
b = tl::unexpected<T2>(s2);
|
||||
swap(a, b);
|
||||
REQUIRE(a.error().i == s2);
|
||||
REQUIRE(b->i == s1);
|
||||
|
||||
a = tl::unexpected<T2>(s1);
|
||||
b = s2;
|
||||
swap(a, b);
|
||||
REQUIRE(a->i == s2);
|
||||
REQUIRE(b.error().i == s1);
|
||||
|
||||
a = tl::unexpected<T2>(s1);
|
||||
b = tl::unexpected<T2>(s2);
|
||||
swap(a, b);
|
||||
REQUIRE(a.error().i == s2);
|
||||
REQUIRE(b.error().i == s1);
|
||||
|
||||
a = s1;
|
||||
b = s2;
|
||||
a.swap(b);
|
||||
REQUIRE(a->i == s2);
|
||||
REQUIRE(b->i == s1);
|
||||
|
||||
a = s1;
|
||||
b = tl::unexpected<T2>(s2);
|
||||
a.swap(b);
|
||||
REQUIRE(a.error().i == s2);
|
||||
REQUIRE(b->i == s1);
|
||||
|
||||
a = tl::unexpected<T2>(s1);
|
||||
b = s2;
|
||||
a.swap(b);
|
||||
REQUIRE(a->i == s2);
|
||||
REQUIRE(b.error().i == s1);
|
||||
|
||||
a = tl::unexpected<T2>(s1);
|
||||
b = tl::unexpected<T2>(s2);
|
||||
a.swap(b);
|
||||
REQUIRE(a.error().i == s2);
|
||||
REQUIRE(b.error().i == s1);
|
||||
}
|
||||
|
||||
TEST_CASE("swap") {
|
||||
|
||||
swap_test<no_throw, no_throw>();
|
||||
swap_test<no_throw, canthrow_move>();
|
||||
swap_test<canthrow_move, no_throw>();
|
||||
|
||||
std::string s1 = "abcdefghijklmnopqrstuvwxyz";
|
||||
std::string s2 = "zyxwvutsrqponmlkjihgfedcbaxxx";
|
||||
tl::expected<no_throw, willthrow_move> a{s1};
|
||||
tl::expected<no_throw, willthrow_move> b{tl::unexpect, s2};
|
||||
should_throw = 1;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
//this seems to break catch on GCC and Clang
|
||||
REQUIRE_THROWS(swap(a, b));
|
||||
#endif
|
||||
|
||||
REQUIRE(a->i == s1);
|
||||
REQUIRE(b.error().i == s2);
|
||||
#include "catch.hpp"
|
||||
#include <tl/expected.hpp>
|
||||
|
||||
struct no_throw {
|
||||
no_throw(std::string i) : i(i) {}
|
||||
std::string i;
|
||||
};
|
||||
struct canthrow_move {
|
||||
canthrow_move(std::string i) : i(i) {}
|
||||
canthrow_move(canthrow_move const &) = default;
|
||||
canthrow_move(canthrow_move &&other) noexcept(false) : i(other.i) {}
|
||||
canthrow_move &operator=(canthrow_move &&) = default;
|
||||
std::string i;
|
||||
};
|
||||
|
||||
bool should_throw = false;
|
||||
struct willthrow_move {
|
||||
willthrow_move(std::string i) : i(i) {}
|
||||
willthrow_move(willthrow_move const &) = default;
|
||||
willthrow_move(willthrow_move &&other) : i(other.i) {
|
||||
if (should_throw)
|
||||
throw 0;
|
||||
}
|
||||
willthrow_move &operator=(willthrow_move &&) = default;
|
||||
std::string i;
|
||||
};
|
||||
static_assert(tl::detail::is_swappable<no_throw>::value, "");
|
||||
|
||||
template <class T1, class T2> void swap_test() {
|
||||
std::string s1 = "abcdefghijklmnopqrstuvwxyz";
|
||||
std::string s2 = "zyxwvutsrqponmlkjihgfedcba";
|
||||
|
||||
tl::expected<T1, T2> a{s1};
|
||||
tl::expected<T1, T2> b{s2};
|
||||
swap(a, b);
|
||||
REQUIRE(a->i == s2);
|
||||
REQUIRE(b->i == s1);
|
||||
|
||||
a = s1;
|
||||
b = tl::unexpected<T2>(s2);
|
||||
swap(a, b);
|
||||
REQUIRE(a.error().i == s2);
|
||||
REQUIRE(b->i == s1);
|
||||
|
||||
a = tl::unexpected<T2>(s1);
|
||||
b = s2;
|
||||
swap(a, b);
|
||||
REQUIRE(a->i == s2);
|
||||
REQUIRE(b.error().i == s1);
|
||||
|
||||
a = tl::unexpected<T2>(s1);
|
||||
b = tl::unexpected<T2>(s2);
|
||||
swap(a, b);
|
||||
REQUIRE(a.error().i == s2);
|
||||
REQUIRE(b.error().i == s1);
|
||||
|
||||
a = s1;
|
||||
b = s2;
|
||||
a.swap(b);
|
||||
REQUIRE(a->i == s2);
|
||||
REQUIRE(b->i == s1);
|
||||
|
||||
a = s1;
|
||||
b = tl::unexpected<T2>(s2);
|
||||
a.swap(b);
|
||||
REQUIRE(a.error().i == s2);
|
||||
REQUIRE(b->i == s1);
|
||||
|
||||
a = tl::unexpected<T2>(s1);
|
||||
b = s2;
|
||||
a.swap(b);
|
||||
REQUIRE(a->i == s2);
|
||||
REQUIRE(b.error().i == s1);
|
||||
|
||||
a = tl::unexpected<T2>(s1);
|
||||
b = tl::unexpected<T2>(s2);
|
||||
a.swap(b);
|
||||
REQUIRE(a.error().i == s2);
|
||||
REQUIRE(b.error().i == s1);
|
||||
}
|
||||
|
||||
TEST_CASE("swap") {
|
||||
|
||||
swap_test<no_throw, no_throw>();
|
||||
swap_test<no_throw, canthrow_move>();
|
||||
swap_test<canthrow_move, no_throw>();
|
||||
|
||||
std::string s1 = "abcdefghijklmnopqrstuvwxyz";
|
||||
std::string s2 = "zyxwvutsrqponmlkjihgfedcbaxxx";
|
||||
tl::expected<no_throw, willthrow_move> a{s1};
|
||||
tl::expected<no_throw, willthrow_move> b{tl::unexpect, s2};
|
||||
should_throw = 1;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
//this seems to break catch on GCC and Clang
|
||||
REQUIRE_THROWS(swap(a, b));
|
||||
#endif
|
||||
|
||||
REQUIRE(a->i == s1);
|
||||
REQUIRE(b.error().i == s2);
|
||||
}
|
@ -1,32 +1,32 @@
|
||||
struct no_throw {
|
||||
no_throw(std::string i) : i(i) {}
|
||||
std::string i;
|
||||
};
|
||||
struct canthrow_move {
|
||||
canthrow_move(std::string i) : i(i) {}
|
||||
canthrow_move(canthrow_move const &) = default;
|
||||
canthrow_move(canthrow_move &&other) noexcept(false) : i(other.i) {}
|
||||
canthrow_move &operator=(canthrow_move &&) = default;
|
||||
std::string i;
|
||||
};
|
||||
|
||||
bool should_throw = false;
|
||||
struct willthrow_move {
|
||||
willthrow_move(std::string i) : i(i) {}
|
||||
willthrow_move(willthrow_move const &) = default;
|
||||
willthrow_move(willthrow_move &&other) : i(other.i) {
|
||||
if (should_throw)
|
||||
throw 0;
|
||||
}
|
||||
willthrow_move &operator=(willthrow_move &&) = default;
|
||||
std::string i;
|
||||
};
|
||||
|
||||
int main() {
|
||||
std::string s1 = "abcdefghijklmnopqrstuvwxyz";
|
||||
std::string s2 = "zyxwvutsrqponmlkjihgfedcbaxxx";
|
||||
tl::expected<no_throw, willthrow_move> a{s1};
|
||||
tl::expected<no_throw, willthrow_move> b{tl::unexpect, s2};
|
||||
should_throw = 1;
|
||||
swap(a, b);
|
||||
struct no_throw {
|
||||
no_throw(std::string i) : i(i) {}
|
||||
std::string i;
|
||||
};
|
||||
struct canthrow_move {
|
||||
canthrow_move(std::string i) : i(i) {}
|
||||
canthrow_move(canthrow_move const &) = default;
|
||||
canthrow_move(canthrow_move &&other) noexcept(false) : i(other.i) {}
|
||||
canthrow_move &operator=(canthrow_move &&) = default;
|
||||
std::string i;
|
||||
};
|
||||
|
||||
bool should_throw = false;
|
||||
struct willthrow_move {
|
||||
willthrow_move(std::string i) : i(i) {}
|
||||
willthrow_move(willthrow_move const &) = default;
|
||||
willthrow_move(willthrow_move &&other) : i(other.i) {
|
||||
if (should_throw)
|
||||
throw 0;
|
||||
}
|
||||
willthrow_move &operator=(willthrow_move &&) = default;
|
||||
std::string i;
|
||||
};
|
||||
|
||||
int main() {
|
||||
std::string s1 = "abcdefghijklmnopqrstuvwxyz";
|
||||
std::string s2 = "zyxwvutsrqponmlkjihgfedcbaxxx";
|
||||
tl::expected<no_throw, willthrow_move> a{s1};
|
||||
tl::expected<no_throw, willthrow_move> b{tl::unexpect, s2};
|
||||
should_throw = 1;
|
||||
swap(a, b);
|
||||
}
|
Reference in New Issue
Block a user