简体   繁体   English

模板的条件编译

[英]Conditional compilation of templates

I am trying to get static_assert to help me avoid null pointers in C++11. 我正在尝试获取static_assert来帮助我避免C ++ 11中的空指针。

The problem seems to be that C++11 require the compiler to compile templates even if they are not instantiated. 问题似乎是C ++ 11要求编译器编译模板,即使未实例化它们也是如此。

I have the following code: 我有以下代码:

#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.
}

I would like this to compile without error. 我希望这个编译没有错误。 But the static_assert is compiled and gives me a compile time error. 但是static_assert已编译,并给了我编译时错误。

Only if the the second instantiation of the ClassA is in the code should it give me a compile time error. 仅当ClassA的第二个实例在代码中时,才给我编译时错误。

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 . 范围从简单的语法错误到您在static_assert中的常量false表达式示例。 §14.6 [temp.res]/p8: §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. 如果无法为模板生成有效的专业化名称,并且该模板未实例化,则该模板格式错误,无需诊断。

I'm rather baffled by all this SFINAE machinery, though. 不过,我对所有这些SFINAE机器都感到困惑。 A simple 一个简单的

template<typename T, typename... Us>
T* create_if_constructible(Us... args) { return new T(args...); }

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". 如果T无法从给定的参数构造出来,那么它已经拒绝编译,因此我不确定这种复杂的割礼将如何帮助您“避免使用空指针”。

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;

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. 或者,如果您偏爱static_assert ,则可能是由于自定义错误消息static_assert ,因此必须确保从理论上讲有一种方法可以生成模板的有效实例。 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 . 这意味着1)您要static_assert依赖的内容必须取决于模板参数,并且2)理论上必须存在使条件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; 
}

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. 这里的关键点在于,编译器不能假定always_false<T>::value始终为false因为以后总是有可能将其设置为true的特殊化设置,因此不允许在模板定义时拒绝它。

In all C++ standards ever, templates are compiled in two phases. 在所有的C ++标准中,模板都是分两个阶段进行编译的。 The second phase is instantiation, but compilation can also fail in phase 1. In particular, syntax errors are detected in phase 1. 第二阶段是实例化,但是在阶段1中编译也可能失败。特别是,在阶段1中检测到语法错误。

In your case, the simpler solution is to leave out the body of the second instantiation. 在您的情况下,更简单的解决方案是省略第二个实例的主体。

Another solution is to use T in the static_assert , so the compiler must delay evaluation to phase 2. Trivially: static_assert(sizeof(T)==0, 另一种解决方案是在static_assert使用T ,因此编译器必须将求值延迟到阶段2。琐碎地: static_assert(sizeof(T)==0,

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM