【发布时间】:2016-11-05 23:42:09
【问题描述】:
到目前为止,我在网上找不到任何 ELI5。对于一个学习项目,我想实现我自己的 is_constructible。有人可以解释一下它是如何工作的吗?
【问题讨论】:
标签: c++ c++11 typetraits c++-standard-library
到目前为止,我在网上找不到任何 ELI5。对于一个学习项目,我想实现我自己的 is_constructible。有人可以解释一下它是如何工作的吗?
【问题讨论】:
标签: c++ c++11 typetraits c++-standard-library
来自cppreference:
[I]如果变量定义
T obj(std::declval<Args>()...);是良构的,value等于true,否则value等于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 包持有。
当为<void, T, Args...> 实例化is_constructible_ 时,编译器会首先尝试实例化特化。只有void_t<...> 的内容在语义上有效,即T(std::declval<Args>()...) 可以正确执行——如is_constructible 的要求中所指定,这才会成功。请注意,我使用的是临时变量而不是局部变量,但据我所知,两者之间的规则不会改变。特化继承自std::true_type,产生true value。
如果无法实例化特化(即T(std::declval<Args>()...) 无效),编译器将退回到总能实例化的通用模板。这个继承自std::false_type,产生falsevalue。
更精确的特征,例如std::is_trivially_constructible,需要更高级的语言规则知识来制作表达式,其有效性应该成为特征的值。如果从语言内部证明这是不可行的,例如使用std::is_standard_layout,那么编译器本身必须提供一个内部函数来检索该值。
【讨论】:
std::is_constructible,因为T(Arg) 等同于C 风格的演员——所以你的is_constructible<intptr_t, int*> 是true,而std 将返回假的。
template <class T, class... Args> struct is_constructible_< void_t<decltype(::new T(std::declval<Args>()...))>, T, Args...> : std::true_type {}; 获取专用模板。