diff --git a/.clang-format b/.clang-format index 1519219..0ac5d23 100644 --- a/.clang-format +++ b/.clang-format @@ -1,18 +1,36 @@ --- Language: Cpp +BasedOnStyle: Microsoft AccessModifierOffset: -4 AlignAfterOpenBracket: BlockIndent AlignArrayOfStructures: Left -AlignConsecutiveAssignments: AcrossComments -AlignConsecutiveBitFields: AcrossComments -AlignConsecutiveDeclarations: AcrossComments -AlignConsecutiveMacros: AcrossComments +AlignConsecutiveAssignments: + Enabled: true + AcrossEmptyLines: false + AcrossComments: true + AlignCompound: false # only for AlignConsecutiveAssignments + PadOperators: true # only for AlignConsecutiveAssignments +AlignConsecutiveBitFields: + Enabled: true + AcrossEmptyLines: false + AcrossComments: true +AlignConsecutiveDeclarations: + Enabled: true + AcrossEmptyLines: false + AcrossComments: true + #AlignFunctionDeclarations: false # only for AlignConsecutiveDeclarations # clang-format 20 + AlignFunctionPointers: false # only for AlignConsecutiveDeclarations +AlignConsecutiveMacros: + Enabled: true + AcrossEmptyLines: false + AcrossComments: true AlignConsecutiveShortCaseStatements: Enabled: true AcrossEmptyLines: false AcrossComments: true + AlignCaseArrows: false AlignCaseColons: false AlignEscapedNewlines: Left AlignOperands: AlignAfterOperator @@ -24,13 +42,17 @@ AllowAllArgumentsOnNextLine: true AllowAllConstructorInitializersOnNextLine: true AllowAllParametersOfDeclarationOnNextLine: true -AllowShortBlocksOnASingleLine: Empty -AllowShortCaseLabelsOnASingleLine: false -AllowShortEnumsOnASingleLine: true -AllowShortFunctionsOnASingleLine: InlineOnly -AllowShortIfStatementsOnASingleLine: Never -AllowShortLambdasOnASingleLine: Inline -AllowShortLoopsOnASingleLine: false +AllowBreakBeforeNoexceptSpecifier: Never + +AllowShortBlocksOnASingleLine: Empty +AllowShortCaseExpressionOnASingleLine: true +AllowShortCaseLabelsOnASingleLine: false +AllowShortCompoundRequirementOnASingleLine: true +AllowShortEnumsOnASingleLine: true +AllowShortFunctionsOnASingleLine: InlineOnly +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: Inline +AllowShortLoopsOnASingleLine: false AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: true @@ -65,16 +87,20 @@ BraceWrapping: SplitEmptyFunction: true SplitEmptyRecord: true SplitEmptyNamespace: true -BracedInitializerIndentWidth: 4 # clang-format 17 +BracedInitializerIndentWidth: 4 +BreakAdjacentStringLiterals: true BreakAfterAttributes: Leave +BreakAfterReturnType: ExceptShortType BreakBeforeBinaryOperators: None # TBD BreakBeforeBraces: Custom BreakBeforeConceptDeclarations: Always BreakBeforeInlineASMColon: Always BreakBeforeTernaryOperators: false BreakConstructorInitializers: BeforeComma +BreakFunctionDefinitionParameters: false BreakInheritanceList: BeforeComma BreakStringLiterals: true +BreakTemplateDeclarations: Yes ColumnLimit: 140 CommentPragmas: "^ IWYU pragma:" # TBD` @@ -129,12 +155,16 @@ IntegerLiteralSeparator: LineEnding: DeriveLF -KeepEmptyLinesAtEOF: true -KeepEmptyLinesAtTheStartOfBlocks: false +KeepEmptyLines: + AtEndOfFile: true + AtStartOfBlock: false + AtStartOfFile: false + LambdaBodyIndentation: Signature -Macros: [] # TBD MacroBlockBegin: "" # TBD MacroBlockEnd: "" # TBD +Macros: [] # TBD +#MainIncludeChar: Quota # clang-format 20 MaxEmptyLinesToKeep: 1 NamespaceIndentation: None NamespaceMacros: [] # TBD A vector of macros which are used to open namespace blocks. @@ -142,17 +172,18 @@ NamespaceMacros: [] # TBD A vector of macros which are used to open namespace bl PPIndentWidth: -1 # default to IndentWidth PackConstructorInitializers: Never -# Penalty is hard to understand, leave it to default +# Penalty is hard to understand, leave it to default(style=Microsoft) #PenaltyBreakAssignment: 2 #PenaltyBreakBeforeFirstCallParameter: 19 #PenaltyBreakComment: 300 #PenaltyBreakFirstLessLess: 120 #PenaltyBreakOpenParenthesis: 0 +#PenaltyBreakScopeResolution: 500 #PenaltyBreakString: 1000 #PenaltyBreakTemplateDeclaration: 10 #PenaltyExcessCharacter: 1000000 #PenaltyIndentedWhitespace: 0 -#PenaltyReturnTypeOnItsOwnLine: 6000 +#PenaltyReturnTypeOnItsOwnLine: 1000 PointerAlignment: Left @@ -171,6 +202,8 @@ RequiresExpressionIndentation: OuterScope ShortNamespaceLines: 20 +SkipMacroDefinitionBody: false + SortIncludes: Never SortUsingDeclarations: false diff --git a/include/zeus/expected.hpp b/include/zeus/expected.hpp index ba2dbef..079f2e3 100644 --- a/include/zeus/expected.hpp +++ b/include/zeus/expected.hpp @@ -1207,7 +1207,7 @@ class expected class U, // class G, // std::enable_if_t && std::is_convertible_v> * = nullptr, // - expected_detail::enable_from_other_expected_t * = nullptr> + expected_detail::enable_from_other_expected_t * = nullptr> constexpr expected(const expected &rhs) // noexcept(std::is_nothrow_constructible_v && std::is_nothrow_constructible_v) : ctor_base(expected_detail::default_constructor_tag {}) @@ -1227,7 +1227,7 @@ class expected class U, // class G, // std::enable_if_t && std::is_convertible_v)> * = nullptr, // - expected_detail::enable_from_other_expected_t * = nullptr> + expected_detail::enable_from_other_expected_t * = nullptr> constexpr explicit expected(const expected &rhs) // noexcept(std::is_nothrow_constructible_v && std::is_nothrow_constructible_v) : ctor_base(expected_detail::default_constructor_tag {}) @@ -1247,7 +1247,7 @@ class expected class U, // class G, // std::enable_if_t && std::is_convertible_v> * = nullptr, // - expected_detail::enable_from_other_expected_t * = nullptr> + expected_detail::enable_from_other_expected_t * = nullptr> constexpr expected(expected &&rhs) // noexcept(std::is_nothrow_constructible_v && std::is_nothrow_constructible_v) : ctor_base(expected_detail::default_constructor_tag {}) @@ -1267,7 +1267,7 @@ class expected class U, // class G, // std::enable_if_t && std::is_convertible_v)> * = nullptr, // - expected_detail::enable_from_other_expected_t * = nullptr> + expected_detail::enable_from_other_expected_t * = nullptr> constexpr explicit expected(expected &&rhs) // noexcept(std::is_nothrow_constructible_v && std::is_nothrow_constructible_v) : ctor_base(expected_detail::default_constructor_tag {}) @@ -1296,7 +1296,7 @@ class expected template< class U = T, std::enable_if_t> * = nullptr, - expected_detail::enable_forward_t * = nullptr> + expected_detail::enable_forward_t * = nullptr> constexpr explicit expected(U &&v) noexcept(std::is_nothrow_constructible_v) : expected(std::in_place, std::forward(v)) { @@ -1307,7 +1307,7 @@ class expected // explicit const unexpected & template< class G, // - std::enable_if_t> * = nullptr, // + std::enable_if_t> * = nullptr, // std::enable_if_t> * = nullptr> explicit constexpr expected(const unexpected &e) noexcept(std::is_nothrow_constructible_v) : impl_base(unexpect, e.error()) @@ -1318,7 +1318,7 @@ class expected // implicit const unexpected & template< class G, // - std::enable_if_t> * = nullptr, // + std::enable_if_t> * = nullptr, // std::enable_if_t> * = nullptr> constexpr expected(unexpected const &e) noexcept(std::is_nothrow_constructible_v) : impl_base(unexpect, e.error()) @@ -1329,7 +1329,7 @@ class expected // explicit unexpected && template< class G, // - std::enable_if_t> * = nullptr, // + std::enable_if_t> * = nullptr, // std::enable_if_t> * = nullptr> explicit constexpr expected(unexpected &&e) noexcept(std::is_nothrow_constructible_v) : impl_base(unexpect, std::move(e.error())) @@ -1340,7 +1340,7 @@ class expected // implicit unexpected && template< class G, // - std::enable_if_t> * = nullptr, // + std::enable_if_t> * = nullptr, // std::enable_if_t> * = nullptr> constexpr expected(unexpected &&e) noexcept(std::is_nothrow_constructible_v) : impl_base(unexpect, std::move(e.error())) @@ -1453,7 +1453,7 @@ class expected (std::is_nothrow_constructible_v || // std::is_nothrow_move_constructible_v || // std::is_nothrow_move_constructible_v) // - > * = nullptr> + > * = nullptr> constexpr expected &operator=(const unexpected &rhs) // noexcept(std::is_nothrow_constructible_v && std::is_nothrow_assignable_v) { @@ -1479,7 +1479,7 @@ class expected (std::is_nothrow_constructible_v || // std::is_nothrow_move_constructible_v || // std::is_nothrow_move_constructible_v) // - > * = nullptr> + > * = nullptr> constexpr expected &operator=(unexpected &&rhs) // noexcept(std::is_nothrow_constructible_v && std::is_nothrow_assignable_v) { @@ -2019,12 +2019,14 @@ class expected return x.error() == y.error(); } } +#if ZEUS_EXPECTED_CPLUSPLUS < 202'002L template [[nodiscard]] friend constexpr std::enable_if_t, bool> operator!=(const expected &x, const expected &y) // noexcept(noexcept(x == y)) { return !(x == y); } +#endif template [[nodiscard]] friend constexpr bool operator==(const expected &x, const T2 &v) // @@ -2039,12 +2041,30 @@ class expected return false; } } +#if ZEUS_EXPECTED_CPLUSPLUS < 202'002L template [[nodiscard]] friend constexpr bool operator!=(const expected &x, const T2 &v) // noexcept(noexcept(x == v)) { return !(x == v); } + template + [[nodiscard]] friend constexpr std::enable_if_t, bool> operator==( + const T2 &v, const expected &x + ) // + noexcept(noexcept(x == v)) + { + return x == v; + } + template + [[nodiscard]] friend constexpr std::enable_if_t, bool> operator!=( + const T2 &v, const expected &x + ) // + noexcept(noexcept(x == v)) + { + return x != v; + } +#endif template [[nodiscard]] friend constexpr bool operator==(const expected &x, const unexpected &e) // @@ -2059,12 +2079,26 @@ class expected return static_cast(x.error() == e.error()); } } +#if ZEUS_EXPECTED_CPLUSPLUS < 202'002L template [[nodiscard]] friend constexpr bool operator!=(const expected &x, const unexpected &e) // noexcept(noexcept(x == e)) { return !(x == e); } + template + [[nodiscard]] friend constexpr bool operator==(const unexpected &e, const expected &x) // + noexcept(noexcept(x == e)) + { + return x == e; + } + template + [[nodiscard]] friend constexpr bool operator!=(const unexpected &e, const expected &x) // + noexcept(noexcept(x == e)) + { + return x != e; + } +#endif }; // standalone swap for non-void value type @@ -2116,7 +2150,7 @@ class expected template< class U, // class G, // - std::enable_if_t> * = nullptr, // + std::enable_if_t> * = nullptr, // expected_detail::enable_from_other_void_expected_t * = nullptr> constexpr expected(const expected &rhs) // noexcept(std::is_nothrow_constructible_v) @@ -2135,7 +2169,7 @@ class expected template< class U, // class G, // - std::enable_if_t> * = nullptr, // + std::enable_if_t> * = nullptr, // expected_detail::enable_from_other_void_expected_t * = nullptr> constexpr explicit expected(const expected &rhs) // noexcept(std::is_nothrow_constructible_v) @@ -2154,7 +2188,7 @@ class expected template< class U, // class G, // - std::enable_if_t> * = nullptr, // + std::enable_if_t> * = nullptr, // expected_detail::enable_from_other_void_expected_t * = nullptr> constexpr expected(expected &&rhs) // noexcept(std::is_nothrow_constructible_v) @@ -2173,7 +2207,7 @@ class expected template< class U, // class G, // - std::enable_if_t> * = nullptr, // + std::enable_if_t> * = nullptr, // expected_detail::enable_from_other_void_expected_t * = nullptr> constexpr explicit expected(expected &&rhs) // noexcept(std::is_nothrow_constructible_v) @@ -2194,7 +2228,7 @@ class expected // explicit const unexpected & template< class G, // - std::enable_if_t> * = nullptr, // + std::enable_if_t> * = nullptr, // std::enable_if_t> * = nullptr> explicit constexpr expected(const unexpected &e) noexcept(std::is_nothrow_constructible_v) : impl_base(unexpect, e.error()) @@ -2205,7 +2239,7 @@ class expected // implicit const unexpected & template< class G, // - std::enable_if_t> * = nullptr, // + std::enable_if_t> * = nullptr, // std::enable_if_t> * = nullptr> constexpr expected(unexpected const &e) noexcept(std::is_nothrow_constructible_v) : impl_base(unexpect, e.error()) @@ -2216,7 +2250,7 @@ class expected // explicit unexpected && template< class G, // - std::enable_if_t> * = nullptr, // + std::enable_if_t> * = nullptr, // std::enable_if_t> * = nullptr> explicit constexpr expected(unexpected &&e) noexcept(std::is_nothrow_constructible_v) : impl_base(unexpect, std::move(e.error())) @@ -2227,7 +2261,7 @@ class expected // implicit unexpected && template< class G, // - std::enable_if_t> * = nullptr, // + std::enable_if_t> * = nullptr, // std::enable_if_t> * = nullptr> constexpr expected(unexpected &&e) noexcept(std::is_nothrow_constructible_v) : impl_base(unexpect, std::move(e.error())) @@ -2280,7 +2314,7 @@ class expected std::enable_if_t< // std::is_constructible_v && // std::is_assignable_v // - > * = nullptr> + > * = nullptr> constexpr expected &operator=(const unexpected &rhs) // noexcept(std::is_nothrow_constructible_v && std::is_nothrow_assignable_v) { @@ -2303,7 +2337,7 @@ class expected std::enable_if_t< // std::is_constructible_v && // std::is_assignable_v // - > * = nullptr> + > * = nullptr> constexpr expected &operator=(unexpected &&rhs) // noexcept(std::is_nothrow_constructible_v && std::is_nothrow_assignable_v) { @@ -2702,12 +2736,14 @@ class expected return x.has_value() || static_cast(x.error() == y.error()); } } +#if ZEUS_EXPECTED_CPLUSPLUS < 202'002L template [[nodiscard]] friend constexpr std::enable_if_t, bool> operator!=(const expected &x, const expected &y) // noexcept(noexcept(x == y)) { return !(x == y); } +#endif template [[nodiscard]] friend constexpr bool operator==(const expected &x, const unexpected &e) // @@ -2722,12 +2758,26 @@ class expected return static_cast(x.error() == e.error()); } } +#if ZEUS_EXPECTED_CPLUSPLUS < 202'002L template [[nodiscard]] friend constexpr bool operator!=(const expected &x, const unexpected &e) // noexcept(noexcept(x == e)) { return !(x == e); } + template + [[nodiscard]] friend constexpr bool operator==(const unexpected &e, const expected &x) // + noexcept(noexcept(x == e)) + { + return x == e; + } + template + [[nodiscard]] friend constexpr bool operator!=(const unexpected &e, const expected &x) // + noexcept(noexcept(x == e)) + { + return x != e; + } +#endif }; // standalone swap for void value type diff --git a/tests/test_expected/CMakeLists.txt b/tests/test_expected/CMakeLists.txt index 160364d..5bd969a 100644 --- a/tests/test_expected/CMakeLists.txt +++ b/tests/test_expected/CMakeLists.txt @@ -4,6 +4,7 @@ set(SOURCES base_tests.cpp monadic_tests.cpp noexcept_tests.cpp + equality_tests.cpp test_expected_main.cpp ) diff --git a/tests/test_expected/equality_tests.cpp b/tests/test_expected/equality_tests.cpp new file mode 100644 index 0000000..f8b9f27 --- /dev/null +++ b/tests/test_expected/equality_tests.cpp @@ -0,0 +1,337 @@ +#include + +#include + +#include +#include + +using namespace zeus; + +namespace +{ + +template +constexpr bool EqualityTester(T const& lhs, U const& rhs) +{ + return (lhs == rhs) == ShouldEqual && (lhs != rhs) != ShouldEqual && (rhs == lhs) == ShouldEqual && (rhs != lhs) != ShouldEqual; +} + +struct Type1 +{ + std::string value; + + Type1(std::string const& v) + : value(v) + { + } + Type1(const char* v) + : value(v) + { + } + Type1(Type1 const&) = delete; + Type1& operator=(Type1 const&) = delete; + Type1(Type1&& other) = default; + Type1& operator=(Type1&&) = default; + ~Type1() = default; + + bool operator==(Type1 const& rhs) const { return value == rhs.value; } +}; + +struct Type2 +{ + std::string value; + + Type2(std::string const& v) + : value(v) + { + } + Type2(const char* v) + : value(v) + { + } + Type2(Type2 const&) = delete; + Type2& operator=(Type2 const&) = delete; + Type2(Type2&& other) = default; + Type2& operator=(Type2&&) = default; + ~Type2() = default; + + bool operator==(Type2 const& rhs) const { return value == rhs.value; } +}; + +inline bool operator==(Type1 const& lhs, Type2 const& rhs) +{ + return lhs.value == rhs.value; +} + +inline bool operator==(Type2 const& lhs, Type1 const& rhs) +{ + return rhs == lhs; +} + +} // namespace + +SCENARIO("equality", "[equality]") +{ + GIVEN("expected (T is not void)") + { + using T = Type1; + using E = Type2; + using Expected = expected; + + WHEN("compare with same type expected") + { + Expected const value1 = "value1"; + Expected const value2 = "value2"; + Expected const value1Copy = "value1"; + Expected const error1 = zeus::unexpected("error1"); + Expected const error2 = zeus::unexpected("error2"); + Expected const error1Copy = zeus::unexpected("error1"); + + WHEN("two same values") + { + CHECK(EqualityTester(value1, value1Copy)); + } + WHEN("two different values") + { + CHECK(EqualityTester(value1, value2)); + } + WHEN("two same errors") + { + CHECK(EqualityTester(error1, error1Copy)); + } + WHEN("two different errors") + { + CHECK(EqualityTester(error1, error2)); + } + WHEN("mixed value and error") + { + CHECK(EqualityTester(value1, error1)); + } + } + WHEN("compare with different type expected") + { + using T2 = Type2; + using E2 = Type1; + static_assert(!std::is_same_v); + static_assert(!std::is_same_v); + using Expected2 = expected; + + Expected const value1 = "value1"; + Expected2 const value2 = "value2"; + Expected2 const value1Same = "value1"; + Expected const error1 = zeus::unexpected("error1"); + Expected2 const error2 = zeus::unexpected("error2"); + Expected2 const error1Same = zeus::unexpected("error1"); + + WHEN("two same values") + { + CHECK(EqualityTester(value1, value1Same)); + } + WHEN("two different values") + { + CHECK(EqualityTester(value1, value2)); + } + WHEN("two same errors") + { + CHECK(EqualityTester(error1, error1Same)); + } + WHEN("two different errors") + { + CHECK(EqualityTester(error1, error2)); + } + WHEN("mixed value and errors") + { + CHECK(EqualityTester(value1, error1)); + } + } + WHEN("compare with same value type T") + { + Expected const value1 = "value1"; + Expected const error1 = zeus::unexpected("error1"); + T const value2 = "value2"; + T const value1Same = "value1"; + + WHEN("two same values") + { + CHECK(EqualityTester(value1, value1Same)); + } + WHEN("two different values") + { + CHECK(EqualityTester(value1, value2)); + } + WHEN("lhs is error") + { + CHECK(EqualityTester(error1, value2)); + } + } + WHEN("compare with different value type T2") + { + using T2 = Type2; + static_assert(!std::is_same_v); + + Expected const value1 = "value1"; + Expected const error1 = zeus::unexpected("error1"); + T2 const value2 = "value2"; + T2 const value1Same = "value1"; + + WHEN("two same values") + { + CHECK(EqualityTester(value1, value1Same)); + } + WHEN("two different values") + { + CHECK(EqualityTester(value1, value2)); + } + WHEN("lhs is error") + { + CHECK(EqualityTester(error1, value2)); + } + } + WHEN("compare with same error type unexpected") + { + Expected const value1 = "value1"; + Expected const error1 = zeus::unexpected("error1"); + auto const error2 = zeus::unexpected("error2"); + auto const error1Same = zeus::unexpected("error1"); + + WHEN("two same errors") + { + CHECK(EqualityTester(error1, error1Same)); + } + WHEN("two different erros") + { + CHECK(EqualityTester(error1, error2)); + } + WHEN("lhs has value") + { + CHECK(EqualityTester(value1, error2)); + } + } + WHEN("compare with different error type unexpected") + { + using E2 = Type1; + static_assert(!std::is_same_v); + + Expected const value1 = "value1"; + Expected const error1 = zeus::unexpected("error1"); + auto const error2 = zeus::unexpected("error2"); + auto const error1Same = zeus::unexpected("error1"); + + WHEN("two same errors") + { + CHECK(EqualityTester(error1, error1Same)); + } + WHEN("two different erros") + { + CHECK(EqualityTester(error1, error2)); + } + WHEN("lhs has value") + { + CHECK(EqualityTester(value1, error2)); + } + } + } + GIVEN("expected") + { + using E = Type1; + using Expected = expected; + + WHEN("compare with same type expected") + { + Expected const value1; + Expected const value2; + Expected const error1 = zeus::unexpected("error1"); + Expected const error2 = zeus::unexpected("error2"); + Expected const error1Copy = zeus::unexpected("error1"); + + WHEN("both have value") + { + CHECK(EqualityTester(value1, value2)); + } + WHEN("two same errors") + { + CHECK(EqualityTester(error1, error1Copy)); + } + WHEN("two different errors") + { + CHECK(EqualityTester(error1, error2)); + } + WHEN("mixed value and error") + { + CHECK(EqualityTester(value1, error1)); + } + } + WHEN("compare with different type expected") + { + using E2 = Type2; + static_assert(!std::is_same_v); + using Expected2 = expected; + + Expected const value1; + Expected2 const value2; + Expected const error1 = zeus::unexpected("error1"); + Expected2 const error2 = zeus::unexpected("error2"); + Expected2 const error1Same = zeus::unexpected("error1"); + + WHEN("both have value") + { + CHECK(EqualityTester(value1, value2)); + } + WHEN("two same errors") + { + CHECK(EqualityTester(error1, error1Same)); + } + WHEN("two different errors") + { + CHECK(EqualityTester(error1, error2)); + } + WHEN("mixed value and errors") + { + CHECK(EqualityTester(value1, error1)); + } + } + WHEN("compare with same error type unexpected") + { + Expected const value1; + Expected const error1 = zeus::unexpected("error1"); + auto const error2 = zeus::unexpected("error2"); + auto const error1Same = zeus::unexpected("error1"); + + WHEN("two same errors") + { + CHECK(EqualityTester(error1, error1Same)); + } + WHEN("two different erros") + { + CHECK(EqualityTester(error1, error2)); + } + WHEN("lhs has value") + { + CHECK(EqualityTester(value1, error2)); + } + } + WHEN("compare with different error type unexpected") + { + using E2 = Type2; + static_assert(!std::is_same_v); + + Expected const value1; + Expected const error1 = zeus::unexpected("error1"); + auto const error2 = zeus::unexpected("error2"); + auto const error1Same = zeus::unexpected("error1"); + + WHEN("two same errors") + { + CHECK(EqualityTester(error1, error1Same)); + } + WHEN("two different erros") + { + CHECK(EqualityTester(error1, error2)); + } + WHEN("lhs has value") + { + CHECK(EqualityTester(value1, error2)); + } + } + } +} diff --git a/tests/test_expected/monadic_tests.cpp b/tests/test_expected/monadic_tests.cpp index a747f63..c68558d 100644 --- a/tests/test_expected/monadic_tests.cpp +++ b/tests/test_expected/monadic_tests.cpp @@ -77,7 +77,7 @@ TEST_CASE("void-T or_else()", "[monadic, void-T]") { using Expected = expected; - { // non-void + { // void using Expected2 = expected; Expected e {};