std::is_constructible<T, Args>是如何实现的?

How is std::is_constructible<T, Args> implemented?

到目前为止,我在网上找不到任何 ELI5。对于一个学习项目,我想实现我自己的 is_constructible。有人可以解释一下它是如何工作的吗?

来自 cppreference:

[I]f the variable definition T obj(std::declval<Args>()...); is well-formed, value is equal to true, else value is false.

可以使用 SFINAE 技术检查代码是否格式正确,例如 void_t<> 技巧(预计将成为 C++1z 标准库的一部分):

template <class...>
using void_t = void;

template <class, class T, class... Args>
struct is_constructible_ : std::false_type {};

template <class T, class... Args>
struct is_constructible_<
    void_t<decltype(T(std::declval<Args>()...))>,
T, Args...> : std::true_type {};

template <class T, class... Args>
using is_constructible = is_constructible_<void_t<>, T, Args...>;

using 跳来跳去首先放置 void_t<> 参数。它通常最后带有默认类型,但该位置由可变 Args 包占据。

is_constructible_<void, T, Args...> 实例化时,编译器首先尝试实例化特化。这只有在 void_t<...> 的内容在语义上有效时才会成功,也就是说,T(std::declval<Args>()...) 可以正确执行——如 is_constructible 的要求中指定的那样。请注意,我使用的是临时变量而不是局部变量,但据我所知,两者之间的规则不会改变。专业化继承自 std::true_type,它产生 true value.

如果无法实例化特化(即 T(std::declval<Args>()...) 无效),编译器将回退到始终可以实例化的通用模板。这个继承自 std::false_type,它产生 false value.

Live on Coliru

更精确的特征,例如 std::is_trivially_constructible,需要更高级的语言规则知识来制作其有效性应成为特征值的表达式。如果从语言内部证明这是不可行的,例如 std::is_standard_layout,那么编译器本身必须提供一个内部函数来检索值。