Qui*_*mby 8 c++ templates static-assert language-lawyer
假设我们要创建一个只能用数字实例化的模板类,否则就不应该编译。我的尝试:
#include <type_traits>
template<typename T, typename = void>
struct OnlyNumbers{
public:
struct C{};
static_assert(std::is_same<C,T>::value, "T is not arithmetic type.");
//OnlyNumbers<C>* ptr;
};
template<typename T>
struct OnlyNumbers<T, std::enable_if_t<std::is_arithmetic_v<T>>>{};
struct Foo{};
int main()
{
OnlyNumbers<int>{}; //Compiles
//OnlyNumbers<Foo>{}; //Error
}
Run Code Online (Sandbox Code Playgroud)
现场演示 -所有三个主要的编译器似乎都能按预期工作。我知道已经有一个类似的问题,答案引用了该标准。接受的答案使用temp.res.8和temp.dep.1来回答该问题。我认为我的问题有所不同,因为我只是在问我的示例,我不确定标准对此的看法。
我认为我的程序不是格式错误的,并且仅当编译器尝试实例化基本模板时,它才应该无法编译。我的推理:
[temp.dep.1]:
在模板内部,某些构造的语义可能因一个实例而异。这样的构造取决于模板参数。
这应该使std::is_same<C,T>::value
依赖T
。
[temp.res.8.1]:
如果模板中的语句或模板未实例化,则无法为模板或constexpr的子语句生成有效的专业化名称;或者
不适用,因为存在有效的专业化,尤其OnlyNumbers<C>
是有效的,并且可以在类内部用于例如定义成员指针variable(ptr
)。实际上,通过删除断言并取消注释ptr
,OnlyNumbers<Foo>
代码行得以编译。
[temp.res.8.2-8.4]不适用。
我的问题是:我的推理正确吗?这是一种使特定[class] *模板static_assert
仅在实例化时无法编译的安全,符合标准的方法吗?
*基本上,我对类模板感兴趣,请随时包含函数模板。但是我认为规则是相同的。
**这意味着没有T
像T=C
从内部使用那样可以从外部实例化模板。即使C
可以通过某种方式访问,我也不认为有一种方法可以引用它,因为它会导致这种递归OnlyNumbers<OnlyNumbers<...>::C>
。
编辑:
为了清楚起见,我知道我可以构造一个表达式,如果其他任何专业都不匹配,则该表达式将完全为假。但这很快就会变得冗长,并且如果专业变更,则容易出错。
静态断言可以直接在类中使用,而不需要做任何复杂的事情。
#include <type_traits>
template<typename T>
struct OnlyNumbers {
static_assert(std::is_arithmetic_v<T>, "T is not arithmetic type.");
// ....
};
Run Code Online (Sandbox Code Playgroud)
在某些情况下,您可能会收到其他错误消息,因为实例化非算术类型的 OnlyNumbers 可能会导致更多编译错误。
我不时使用的一个技巧是
#include <type_traits>
template<typename T>
struct OnlyNumbers {
static_assert(std::is_arithmetic_v<T>, "T is not arithmetic type.");
using TT = std::conditional_t<std::is_arithmetic_v<T>,T,int>;
// ....
};
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您的类将使用有效类型 int 进行实例化。由于静态断言无论如何都会失败,因此这不会产生负面影响。