模板的条件编译 [英] Conditional compilation of templates

查看:176
本文介绍了模板的条件编译的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试获取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_asserts, 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_asserting 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.

这篇关于模板的条件编译的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆