Я попытался реализовать шаблон значений, аналогичный std::is_constructible
, за исключением того, что он имеет значение true, только когда тип скопирован в среде constexpr (т.е. его конструктор копирования является constexpr). Я пришел к следующему коду:
#include <type_traits>
struct Foo {
constexpr Foo() = default;
constexpr Foo(const Foo&) = default;
};
struct Bar {
constexpr Bar() = default;
Bar(const Bar&);
};
namespace detail {
template <int> using Sink = std::true_type;
template<typename T> constexpr auto constexpr_copiable(int) -> Sink<(T(T()),0)>;
template<typename T> constexpr auto constexpr_copiable(...) -> std::false_type;
}
template<typename T> struct is_constexpr_copiable : decltype(detail::constexpr_copiable<T>(0)){ };
static_assert( is_constexpr_copiable<Foo>::value, "");
static_assert(!is_constexpr_copiable<Bar>::value, "");
Теперь я спрашиваю себя, соответствует ли это стандарту, поскольку компиляторы, похоже, не согласны с выходом. https://godbolt.org/g/Aaqoah
Изменить (функции С++ 17):
При внедрении несколько другого is_constexpr_constructible_from
, с новым типом шаблона автоматического типа non-type С++ 17, я снова нашел разницу между компиляторами, когда разыменовал nullptr в выражении constexpr с помощью SFINAE
.
#include <type_traits>
struct Foo {
constexpr Foo() = default;
constexpr Foo(const Foo&) = default;
constexpr Foo(const Foo*f):Foo(*f) {};
};
struct Bar {
constexpr Bar() = default;
Bar(const Bar&);
};
namespace detail {
template <int> struct Sink { using type = std::true_type; };
template<typename T, auto... t> constexpr auto constexpr_constructible_from(int) -> typename Sink<(T(t...),0)>::type;
template<typename T, auto... t> constexpr auto constexpr_constructible_from(...) -> std::false_type;
}
template<typename T, auto... t> struct is_constexpr_constructible_from : decltype(detail::constexpr_constructible_from<T, t...>(0)){ };
constexpr Foo foo;
constexpr Bar bar;
static_assert( is_constexpr_constructible_from<Foo, &foo>::value, "");
static_assert(!is_constexpr_constructible_from<Foo, nullptr>::value, "");
static_assert(!is_constexpr_constructible_from<Bar, &bar>::value, "");
int main() {}