以下程序在使用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>();
}
这令人困惑。 foo
int
显然无法构建main
!如果我将int main() {
foo(0);
}
更改为以下内容,则由于静态断言失败,两个编译器都会拒绝它:
{{1}}
两个编译器怎么说它是可构造的?
答案 0 :(得分:22)
这是标准所说的(§20.9.5/ 6),我强调:
给出以下函数原型:
template <class T> typename add_rvalue_reference<T>::type create();
模板特化的谓词条件 当且仅当,
is_constructible<T, Args...>
才会得到满足 对于一些发明的人来说,下面的变量定义会很好 变量t
:T t(create<Args>()...);
[注意:这些令牌永远不会被解释为函数 宣言。 -end note ]
执行访问检查,就好像在与
T
和。无关的上下文中一样 任何Args
。 只有当前上下文的有效性 考虑变量初始化。 [注意:评估 初始化可能导致副作用,例如实例化 类模板特化和函数模板特化, 生成隐式定义的函数,等等。这样的一面 效果不在“直接上下文”中,并且可能导致 程序不正确。 -end note ]
断言仅在实例化模板构造函数时失败。但是,正如在注释中清除的那样,该断言不在所考虑的变量定义的直接上下文中,因此不会影响其“有效性”。因此,编译器可以将该定义计为有效,从而声称foo
确实可以从int
构建,即使实际尝试从foo
构造int
也会导致一个不正确的计划。
请注意,编译器也被允许,而不是让is_constructible
产生错误,只是根据断言拒绝原始程序,即使两者都没有。
答案 1 :(得分:5)
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>();
}