【发布时间】:2019-06-16 12:49:53
【问题描述】:
假设我们要创建一个只能用数字实例化的模板类,否则不应该编译。我的尝试:
#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
}
Live demo - 所有三个主要编译器似乎都按预期工作。我知道已经有一个类似的question 的答案引用了标准。接受的答案使用temp.res.8 和temp.dep.1 来回答该问题。我认为我的问题有点不同,因为我准确地询问了我的示例,并且我不确定标准对此的看法。
我认为我的程序不是格式错误的,并且当且仅当编译器尝试实例化基本模板时它才应该编译失败。 我的推理:
-
[temp.dep.1]:
在模板内部,一些结构的语义可能因实例而异。这样的构造取决于模板参数。
这应该使
std::is_same<C,T>::value依赖于T。 -
[temp.res.8.1]:
不能为模板或 constexpr 的子语句生成有效的特化,如果模板内的语句和模板未实例化,或
不适用,因为存在有效的特化,特别是
OnlyNumbers<C>是有效的,可以在类中使用,例如定义一个成员指针变量(ptr)。实际上,通过删除断言并取消注释ptr、OnlyNumbers<Foo>行代码编译。 [temp.res.8.2 - 8.4] 不适用。
- [temp.res.8.5] 我认为这也不适用,但我不能说我完全理解这一部分。
我的问题是:我的推理正确吗?这是使特定 [class]* 模板无法使用 static_assert if** 且仅在实例化时无法编译的安全且符合标准的方法吗?
*我主要对类模板感兴趣,请随意包含函数模板。但我认为规则是一样的。
**这意味着没有T 可以用来从外部实例化模板,就像T=C 可以从内部使用一样。即使C 可以以某种方式访问,我认为没有办法引用它,因为它会导致这种递归OnlyNumbers<OnlyNumbers<...>::C>。
编辑:
澄清一下,我知道如果没有其他专业匹配,我可以构造一个完全错误的表达式。但这很快就会变得冗长,而且如果专业发生变化,很容易出错。
【问题讨论】:
标签: c++ templates language-lawyer static-assert