我试图实现一个类似于std::is_constructible
的值模板,但只有当该类型在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
编辑(c ++ 17功能):
在使用c ++ 17的新自动非类型模板类型实现稍微不同的is_constexpr_constructible_from
时,我再次发现编译器之间存在差异,当使用{取消引用constexpr表达式中的nullptr时{1}}。
SFINAE
编辑:(2018年4月)
<德尔> 既然两个编译器都认为支持C ++ 17,我发现下面的代码工作得更好(不需要`T`上的默认构造函数),但仅限于clang。一切都仍然相同,但用以下内容替换命名空间`detail`: 命名空间细节 template struct Sink {}; 模板constexpr自动接收器(S) - &gt;的std :: true_type; template constexpr auto try_copy() - &gt;下沉; template constexpr auto constexpr_copiable(int) - &gt; decltype(水槽(标准:: declval,0)&GT;&GT;())); template constexpr auto constexpr_copiable(...) - &gt;的std :: false_type; } https://godbolt.org/g/3fB8jt 这非常深入到关于未评估上下文的标准的部分内容,并且两个编译器都拒绝允许用`const T&amp;`替换`const T *`并使用`std :: declval()`而不是`nullptr`-cast。如果我确认clang的行为是可接受的标准化行为,我会将此版本提升到一个答案,因为它只需要确切的要求。 德尔> Clang在评估#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() {}
的未评估操作数时接受一些未定义的行为,解除引用nullptr
。