blob: 8cd27b75f64c2511226cd32937daabbf04a8a16b [file] [edit]
//===----------------------------------------------------------------------===//
//
// 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<constexpr-param T>
// friend constexpr auto operator+(T) noexcept -> constant_wrapper<(+T::value)>
// { return {}; }
// template<constexpr-param T>
// friend constexpr auto operator-(T) noexcept -> constant_wrapper<(-T::value)>
// { return {}; }
// template<constexpr-param T>
// friend constexpr auto operator~(T) noexcept -> constant_wrapper<(~T::value)>
// { return {}; }
// template<constexpr-param T>
// friend constexpr auto operator!(T) noexcept -> constant_wrapper<(!T::value)>
// { return {}; }
// template<constexpr-param T>
// friend constexpr auto operator&(T) noexcept -> constant_wrapper<(&T::value)>
// { return {}; }
// template<constexpr-param T>
// friend constexpr auto operator*(T) noexcept -> constant_wrapper<(*T::value)>
// { return {}; }
#include <cassert>
#include <concepts>
#include <utility>
#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 <class T>
concept HasPlus = requires(T t) {
{ +t };
};
template <class T>
concept HasMinus = requires(T t) {
{ -t };
};
template <class T>
concept HasBitNot = requires(T t) {
{ ~t };
};
template <class T>
concept HasNot = requires(T t) {
{ !t };
};
template <class T>
concept HasBitAnd = requires(T t) {
{ &t };
};
template <class T>
concept HasDeref = requires(T t) {
{ *t };
};
template <class T>
concept HasNoexceptPlus = requires(T t) {
{ +t } noexcept;
};
template <class T>
concept HasNoexceptMinus = requires(T t) {
{ -t } noexcept;
};
template <class T>
concept HasNoexceptBitNot = requires(T t) {
{ ~t } noexcept;
};
template <class T>
concept HasNoexceptNot = requires(T t) {
{ !t } noexcept;
};
template <class T>
concept HasNoexceptBitAnd = requires(T t) {
{ &t } noexcept;
};
template <class T>
concept HasNoexceptDeref = requires(T t) {
{ *t } noexcept;
};
static_assert(HasPlus<std::constant_wrapper<WithOps{42}>>);
static_assert(HasMinus<std::constant_wrapper<WithOps{42}>>);
static_assert(HasBitNot<std::constant_wrapper<WithOps{42}>>);
static_assert(HasNot<std::constant_wrapper<WithOps{42}>>);
static_assert(HasBitAnd<std::constant_wrapper<WithOps{42}>>);
static_assert(HasDeref<std::constant_wrapper<WithOps{42}>>);
static_assert(HasNoexceptPlus<std::constant_wrapper<WithOps{42}>>);
static_assert(HasNoexceptMinus<std::constant_wrapper<WithOps{42}>>);
static_assert(HasNoexceptBitNot<std::constant_wrapper<WithOps{42}>>);
static_assert(HasNoexceptNot<std::constant_wrapper<WithOps{42}>>);
static_assert(HasNoexceptBitAnd<std::constant_wrapper<WithOps{42}>>);
static_assert(HasNoexceptDeref<std::constant_wrapper<WithOps{42}>>);
static_assert(HasNoexceptPlus<std::constant_wrapper<42>>);
static_assert(HasNoexceptMinus<std::constant_wrapper<42>>);
static_assert(HasNoexceptBitNot<std::constant_wrapper<42>>);
static_assert(HasNoexceptNot<std::constant_wrapper<42>>);
static_assert(HasNoexceptBitAnd<std::constant_wrapper<42>>);
static_assert(!HasDeref<std::constant_wrapper<42>>);
static_assert(!HasPlus<std::constant_wrapper<NoOps{}>>);
static_assert(!HasMinus<std::constant_wrapper<NoOps{}>>);
static_assert(!HasBitNot<std::constant_wrapper<NoOps{}>>);
static_assert(!HasNot<std::constant_wrapper<NoOps{}>>);
// TODO: Remove this guard when Clang 21 is no longer supported.
#if defined(TEST_CLANG_VER) && TEST_CLANG_VER >= 2200 // https://llvm.org/PR151531
static_assert(HasBitAnd<std::constant_wrapper<NoOps{}>>);
#endif
static_assert(!HasDeref<std::constant_wrapper<NoOps{}>>);
// 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<std::constant_wrapper<OpsReturnNonStructural{42}>>);
static_assert(HasMinus<std::constant_wrapper<OpsReturnNonStructural{42}>>);
static_assert(HasBitNot<std::constant_wrapper<OpsReturnNonStructural{42}>>);
static_assert(HasNot<std::constant_wrapper<OpsReturnNonStructural{42}>>);
static_assert(HasBitAnd<std::constant_wrapper<OpsReturnNonStructural{42}>>);
static_assert(HasDeref<std::constant_wrapper<OpsReturnNonStructural{42}>>);
static_assert(!HasNoexceptPlus<std::constant_wrapper<OpsReturnNonStructural{42}>>);
static_assert(!HasNoexceptMinus<std::constant_wrapper<OpsReturnNonStructural{42}>>);
static_assert(!HasNoexceptBitNot<std::constant_wrapper<OpsReturnNonStructural{42}>>);
static_assert(!HasNoexceptNot<std::constant_wrapper<OpsReturnNonStructural{42}>>);
static_assert(!HasNoexceptBitAnd<std::constant_wrapper<OpsReturnNonStructural{42}>>);
static_assert(!HasNoexceptDeref<std::constant_wrapper<OpsReturnNonStructural{42}>>);
constexpr bool test() {
{
// int
std::constant_wrapper<42> cw42;
std::same_as<std::constant_wrapper<42>> decltype(auto) result = +cw42;
static_assert(result == 42);
std::same_as<std::constant_wrapper<-42>> decltype(auto) result2 = -cw42;
static_assert(result2 == -42);
std::same_as<std::constant_wrapper<~42>> decltype(auto) result3 = ~cw42;
static_assert(result3 == ~42);
std::same_as<std::constant_wrapper<!42>> decltype(auto) result4 = !cw42;
static_assert(result4 == !42);
std::same_as<std::constant_wrapper<&cw42.value>> decltype(auto) result5 = &cw42;
static_assert(result5 == &cw42.value);
}
{
// WithOps
std::constant_wrapper<WithOps{42}> cwWithOps;
std::same_as<std::constant_wrapper<WithOps{42}>> decltype(auto) result = +cwWithOps;
static_assert(result.value.value == 42);
std::same_as<std::constant_wrapper<WithOps{-42}>> decltype(auto) result2 = -cwWithOps;
static_assert(result2.value.value == -42);
std::same_as<std::constant_wrapper<WithOps{~42}>> decltype(auto) result3 = ~cwWithOps;
static_assert(result3.value.value == ~42);
std::same_as<std::constant_wrapper<WithOps{!42}>> decltype(auto) result4 = !cwWithOps;
static_assert(result4.value.value == !42);
std::same_as<std::constant_wrapper<WithOps{84}>> decltype(auto) result5 = &cwWithOps;
static_assert(result5.value.value == 84);
std::same_as<std::constant_wrapper<WithOps{0}>> decltype(auto) result6 = *cwWithOps;
static_assert(result6.value.value == 0);
}
{
// Return non-structural type
// Will use underlying type's runtime operators
std::constant_wrapper<OpsReturnNonStructural{42}> cwOpsReturnNonStructural;
std::same_as<NonStructural> decltype(auto) result = +cwOpsReturnNonStructural;
assert(result.get() == 42);
std::same_as<NonStructural> decltype(auto) result2 = -cwOpsReturnNonStructural;
assert(result2.get() == -42);
std::same_as<NonStructural> decltype(auto) result3 = ~cwOpsReturnNonStructural;
assert(result3.get() == ~42);
std::same_as<NonStructural> decltype(auto) result4 = !cwOpsReturnNonStructural;
assert(result4.get() == !42);
std::same_as<NonStructural> decltype(auto) result5 = &cwOpsReturnNonStructural;
assert(result5.get() == 84);
std::same_as<NonStructural> decltype(auto) result6 = *cwOpsReturnNonStructural;
assert(result6.get() == 0);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}