模板的条件编译
我正在尝试获取static_assert来帮助我避免C ++ 11中的空指针。
I am trying to get static_assert to help me avoid null pointers in C++11.
问题似乎是C ++ 11要求编译器执行以下操作:
The problem seems to be that C++11 require the compiler to compile templates even if they are not instantiated.
我有以下代码:
#include <type_traits>
template<typename T, typename... Us>
std::enable_if_t< std::is_constructible<T, Us...>::value == true, T * >
create_if_constructible(Us... args) { return new T(args...); }
template<typename T, typename... Us>
std::enable_if_t< std::is_constructible<T, Us...>::value == false, T * >
create_if_constructible(Us... args) {
static_assert( false, "Class T constructor does not match argument list.");
return nullptr;
}
struct ClassA {
ClassA(int a, string b) {}
};
void foo() {
ClassA *a = create_if_constructible<ClassA>(1, "Hello");
// ClassA *b = create_if_constructible<ClassA>(1, "Hello", "world"); // I want compile time error here.
}
我希望它可以编译而不会出错。但是static_assert会被编译,并给我一个编译时错误。
I would like this to compile without error. But the static_assert is compiled and gives me a compile time error.
仅当ClassA的第二个实例在代码中时,它才会给我一个编译时错误。
Only if the the second instantiation of the ClassA is in the code should it give me a compile time error.
标准允许(但不要求)编译器诊断无法为其生成有效实例化的模板。范围从简单的语法错误到 static_assert
中的常量 false
表达式的示例。 §14.6[temp.res] / p8:
The standard permits, but does not require, compilers to diagnose templates for which no valid instantiation can be generated. This can range from simple syntax errors to your example of a constant false
expression in a static_assert
. §14.6 [temp.res]/p8:
如果无法为模板生成有效的专业化名称,并且该
模板未实例化,模板格式错误,不需要
诊断。
If no valid specialization can be generated for a template, and that template is not instantiated, the template is ill-formed, no diagnostic required.
我对这一切感到困惑不过,SFINAE机械。一个简单的
I'm rather baffled by all this SFINAE machinery, though. A simple
template<typename T, typename... Us>
T* create_if_constructible(Us... args) { return new T(args...); }
如果 T
为无法根据给定的参数进行构造,因此我不确定这种复杂的割礼将如何帮助您避免使用空指针。
already refuses to compile if T
is not constructible from the parameter given, so I'm not sure how this complex circumlocution will help you "avoid null pointers".
无论如何,一种简单的选择
Regardless, a simple way to make choosing the second function template a compile-time error is to explicitly delete it.
template<typename T, typename... Us>
std::enable_if_t< std::is_constructible<T, Us...>::value == false, T * >
create_if_constructible(Us... args) = delete;
或者,如果您偏爱 static_assert
s,也许由于自定义错误消息,您必须确保从理论上讲有一种方法可以生成模板的有效实例。这意味着1)您 static_assert
所依赖的内容必须取决于模板参数,并且2)从理论上讲,必须有一种条件使 true
。一种简单的方法是使用辅助模板:
Alternatively, if you are partial to static_assert
s, perhaps because of the custom error message, you must ensure that there is theoretically a way to generate a valid instantiation of your template. That means that 1) what you are static_assert
ing on must depend on a template argument, and 2) there must be theoretically a way for the condition to be true
. A simple way is to use an auxiliary template:
template<class> class always_false : std::false_type {};
template<typename T, typename... Us>
std::enable_if_t< std::is_constructible<T, Us...>::value == false, T * >
create_if_constructible(Us... args) {
static_assert( always_false<T>::value, "Class T constructor does not match argument list.");
return nullptr;
}
此处的关键点是编译器无法假定 always_false< T> :: value
始终为 false
,因为以后总是可能会有一个专门化设置将其设置为 true
,因此不允许在模板定义时拒绝它。
The key point here is that the compiler cannot assume that always_false<T>::value
is always false
because it is always possible that there's a specialization later that sets it to true
, and so it is not allowed to reject this at template definition time.