尝试根据数组大小的有效性进行特化:
// base template
template<int p, typename T = void>
struct absolute {
operator int () const { return 0; }
};
// positive case template
template<int p>
struct absolute<p, typename std::void_t<int[p]>> {
operator int () const { return p; }
};
// negative case template
template<int p>
struct absolute<p, typename std::void_t<int[-p]>> {
operator int () const { return -p; }
};
int main() {
std::cout << absolute<5>() << std::endl;
std::cout << absolute<-5>() << std::endl;
std::cout << absolute<0>() << std::endl;
}
问题#1:
以上代码works nicely with gcc but fails to compile with clang .
Clang 生成错误:重新定义模板结构“绝对”
谁是对的?
问题#2:
Both with gcc and with clang (如果我们移除负面特化以将 clang 带回游戏中),不清楚为什么
absolute<0>()
选择基本模板。 There is nothing wrong与 int[0]
以及 std::void_t<int[0]>
这似乎更专业:// base template
template<int p, typename T = void>
struct absolute {
operator int () const { return -1; }
};
// positive case template
template<int p>
struct absolute<p, typename std::void_t<int[p]>> {
operator int () const { return p; }
};
int main() {
std::cout << absolute<5>() << std::endl; // 5
std::cout << absolute<0>() << std::endl; // -1, why not 0?
}
并且...如果只是在没有实现的情况下声明了基本模板,则为:
// base template
template<int p, typename T = void>
struct absolute;
Both gcc and clang would fail to compile , 投诉 不完整类型的无效使用 电话:
absolute<0>()
.即使它似乎适合特殊情况。这是为什么?
最佳答案
关于Clang的重定义错误,见this question .
原来是别名模板的模板id,比如std::void_t
将简单地替换为它们的别名类型,而不检查替换失败的参数。这被更改为 CWG issue 1558 .这只是将标准更改为要求在要完成的模板参数中替换失败,但并未阐明在替换别名后是否等效的两个模板是否应被视为等效。 Clang 认为它们是等价的,但 GCC 不是。这是开放的CWG issue 1980 .
与 -pedantic-errors
GCC 已经报告了一个硬错误
std::cout << absolute<5>() << std::endl;
在特化
template<int p>
struct absolute<p, typename std::void_t<int[-p]>>
因为据说数组大小不是常量表达式。数组的大小必须是类型
std::size_t
的转换后的常量表达式.转换后的常量表达式只能使用非缩小转换。所以-p
是真的与 p = 5
转换为 std::size_t
不是常量表达式,使得类型 int[-p]
格式错误,但我认为这应该导致替换失败,而不是硬错误。 [temp.deduct/8] C++17 标准(草案 N4659)说:If a substitution results in an invalid type or expression, type deduction fails. An invalid type or expression is one that would be ill-formed, with a diagnostic required, if written using the substituted arguments.
这适用于这里。引用后给出的非规范示例甚至包括负数组大小作为替换失败的示例。
特别奇怪的是对于
absolute<-5>()
GCC 不报告等效错误template<int p>
struct absolute<p, typename std::void_t<int[p]>>
特化,其中
int[p]
将评估为 int[-5]
它也没有转换后的常量表达式大小。absolute<0>()
选择主模板,因为数组大小需要大于零,这使得部分特化都不可行。零大小数组是一种语言扩展,可以通过 -pedantic-errors
禁用。在 GCC 和 Clang 中。
关于c++ - 基于数组大小有效性的特化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60715854/