//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // REQUIRES: std-at-least-c++26 // constant_wrapper // template // friend constexpr auto operator+(T) noexcept -> constant_wrapper<(+T::value)> // { return {}; } // template // friend constexpr auto operator-(T) noexcept -> constant_wrapper<(-T::value)> // { return {}; } // template // friend constexpr auto operator~(T) noexcept -> constant_wrapper<(~T::value)> // { return {}; } // template // friend constexpr auto operator!(T) noexcept -> constant_wrapper<(!T::value)> // { return {}; } // template // friend constexpr auto operator&(T) noexcept -> constant_wrapper<(&T::value)> // { return {}; } // template // friend constexpr auto operator*(T) noexcept -> constant_wrapper<(*T::value)> // { return {}; } #include #include #include #include "helpers.h" struct WithOps { int value; constexpr WithOps(int v) : value(v) {} friend constexpr auto operator+(WithOps w) { return WithOps{+w.value}; } friend constexpr auto operator-(WithOps w) { return WithOps{-w.value}; } friend constexpr auto operator~(WithOps w) { return WithOps{~w.value}; } friend constexpr auto operator!(WithOps w) { return WithOps{!w.value}; } friend constexpr auto operator&(WithOps w) { return WithOps{w.value + 42}; } friend constexpr auto operator*(WithOps w) { return WithOps{w.value - 42}; } }; struct OpsReturnNonStructural { int value; constexpr OpsReturnNonStructural(int v) : value(v) {} friend constexpr auto operator+(OpsReturnNonStructural o) { return NonStructural{+o.value}; } friend constexpr auto operator-(OpsReturnNonStructural o) { return NonStructural{-o.value}; } friend constexpr auto operator~(OpsReturnNonStructural o) { return NonStructural{~o.value}; } friend constexpr auto operator!(OpsReturnNonStructural o) { return NonStructural{!o.value}; } friend constexpr auto operator&(OpsReturnNonStructural o) { return NonStructural{o.value + 42}; } friend constexpr auto operator*(OpsReturnNonStructural o) { return NonStructural{o.value - 42}; } }; struct NoOps {}; template concept HasPlus = requires(T t) { { +t }; }; template concept HasMinus = requires(T t) { { -t }; }; template concept HasBitNot = requires(T t) { { ~t }; }; template concept HasNot = requires(T t) { { !t }; }; template concept HasBitAnd = requires(T t) { { &t }; }; template concept HasDeref = requires(T t) { { *t }; }; template concept HasNoexceptPlus = requires(T t) { { +t } noexcept; }; template concept HasNoexceptMinus = requires(T t) { { -t } noexcept; }; template concept HasNoexceptBitNot = requires(T t) { { ~t } noexcept; }; template concept HasNoexceptNot = requires(T t) { { !t } noexcept; }; template concept HasNoexceptBitAnd = requires(T t) { { &t } noexcept; }; template concept HasNoexceptDeref = requires(T t) { { *t } noexcept; }; static_assert(HasPlus>); static_assert(HasMinus>); static_assert(HasBitNot>); static_assert(HasNot>); static_assert(HasBitAnd>); static_assert(HasDeref>); static_assert(HasNoexceptPlus>); static_assert(HasNoexceptMinus>); static_assert(HasNoexceptBitNot>); static_assert(HasNoexceptNot>); static_assert(HasNoexceptBitAnd>); static_assert(HasNoexceptDeref>); static_assert(HasNoexceptPlus>); static_assert(HasNoexceptMinus>); static_assert(HasNoexceptBitNot>); static_assert(HasNoexceptNot>); static_assert(HasNoexceptBitAnd>); static_assert(!HasDeref>); static_assert(!HasPlus>); static_assert(!HasMinus>); static_assert(!HasBitNot>); static_assert(!HasNot>); static_assert(HasBitAnd>); static_assert(!HasDeref>); // The operators from constant_wrapper do not exist, but they can be implicited converted // to the underlying type and use its operators instead. static_assert(HasPlus>); static_assert(HasMinus>); static_assert(HasBitNot>); static_assert(HasNot>); static_assert(HasBitAnd>); static_assert(HasDeref>); static_assert(!HasNoexceptPlus>); static_assert(!HasNoexceptMinus>); static_assert(!HasNoexceptBitNot>); static_assert(!HasNoexceptNot>); static_assert(!HasNoexceptBitAnd>); static_assert(!HasNoexceptDeref>); constexpr bool test() { { // int std::constant_wrapper<42> cw42; std::same_as> decltype(auto) result = +cw42; static_assert(result == 42); std::same_as> decltype(auto) result2 = -cw42; static_assert(result2 == -42); std::same_as> decltype(auto) result3 = ~cw42; static_assert(result3 == ~42); std::same_as> decltype(auto) result4 = !cw42; static_assert(result4 == !42); std::same_as> decltype(auto) result5 = &cw42; static_assert(result5 == &cw42.value); } { // WithOps std::constant_wrapper cwWithOps; std::same_as> decltype(auto) result = +cwWithOps; static_assert(result.value.value == 42); std::same_as> decltype(auto) result2 = -cwWithOps; static_assert(result2.value.value == -42); std::same_as> decltype(auto) result3 = ~cwWithOps; static_assert(result3.value.value == ~42); std::same_as> decltype(auto) result4 = !cwWithOps; static_assert(result4.value.value == !42); std::same_as> decltype(auto) result5 = &cwWithOps; static_assert(result5.value.value == 84); std::same_as> decltype(auto) result6 = *cwWithOps; static_assert(result6.value.value == 0); } { // Return non-structural type // Will use underlying type's runtime operators std::constant_wrapper cwOpsReturnNonStructural; std::same_as decltype(auto) result = +cwOpsReturnNonStructural; assert(result.get() == 42); std::same_as decltype(auto) result2 = -cwOpsReturnNonStructural; assert(result2.get() == -42); std::same_as decltype(auto) result3 = ~cwOpsReturnNonStructural; assert(result3.get() == ~42); std::same_as decltype(auto) result4 = !cwOpsReturnNonStructural; assert(result4.get() == !42); std::same_as decltype(auto) result5 = &cwOpsReturnNonStructural; assert(result5.get() == 84); std::same_as decltype(auto) result6 = *cwOpsReturnNonStructural; assert(result6.get() == 0); } return true; } int main(int, char**) { test(); static_assert(test()); return 0; }