R. *_*des 14 c++ templates constructor type-traits c++11
当使用GCC 4.7和clang 3.2编译时,以下程序产生"1"作为输出.
#include <type_traits>
struct foo {
template<typename T>
foo(T) {
static_assert(not std::is_same<int, T>(), "no ints please");
}
};
#include <iostream>
int main() {
std::cout << std::is_constructible<foo, int>();
}
Run Code Online (Sandbox Code Playgroud)
这令人困惑.foo
显然不是可以构建的int
!如果我改为main
以下,由于静态断言失败,两个编译器都拒绝它:
int main() {
foo(0);
}
Run Code Online (Sandbox Code Playgroud)
两个编译器怎么说它是可构造的?
R. *_*des 22
这就是标准所说的(§20.9.5/ 6),我的重点是:
给出以下函数原型:
Run Code Online (Sandbox Code Playgroud)template <class T> typename add_rvalue_reference<T>::type create();
is_constructible<T, Args...>
当且仅当以下变量定义适用于某些发明变量时,才应满足模板特化的谓词条件t
:Run Code Online (Sandbox Code Playgroud)T t(create<Args>()...);
[ 注意:这些标记永远不会被解释为函数声明.- 尾注 ]
执行访问检查就好像在与其无关的上下文
T
中执行Args
.仅考虑变量初始化的直接上下文的有效性.[ 注意:初始化的评估可能会导致副作用,例如类模板特化和函数模板特化的实例化,隐式定义函数的生成等等.这种副作用不在"直接背景"中,并且可能导致程序形成不良.- 尾注 ]
断言仅在实例化模板构造函数时失败.但是,正如在注释中清除的那样,该断言不在所考虑的变量定义的直接上下文中,因此不会影响其"有效性".因此编译器可以将该定义视为有效,因此声称它foo
确实是可构造的int
,即使实际上是试图foo
从int
一个不正确的程序中构造一个结果.
请注意,编译器也被允许,而不是is_constructible
产生错误,只是基于断言拒绝原始程序,即使没有人这样做.
foo2
是你的foo
. foo1
是一个做你想做的foo
事的foo .
#include <type_traits>
#include <utility>
struct foo1 {
template<typename T,typename=typename std::enable_if< !std::is_same<int, T>::value >::type>
foo1(T) {
static_assert(not std::is_same<int, T>(), "no ints please");
}
};
struct foo2 {
template<typename T>
foo2(T) {
static_assert(not std::is_same<int, T>(), "no ints please");
}
};
#include <iostream>
int main() {
std::cout << std::is_constructible<foo1, int>();
std::cout << std::is_constructible<foo2, int>();
}
Run Code Online (Sandbox Code Playgroud)