实现is_constexpr_copiable

时间:2017-03-30 14:18:14

标签: c++ templates language-lawyer c++17 constexpr

我试图实现一个类似于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

https://godbolt.org/g/830SCU

编辑:(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

0 个答案:

没有答案