【发布时间】:2019-02-26 22:46:14
【问题描述】:
考虑代码:
class Test {
public:
template<int N> auto foo() {}
template<> auto foo<0>() { return 7; }
template<int N> void bar() {}
template<> int bar<0>() { return 7; }
};
我已经用不同的编译器测试了代码(通过Compiler Explorer)。
如果 Clang 7.0.0 foo 编译,而 bar 给出错误:
:8:20: 错误:没有函数模板与函数模板匹配 专业化“酒吧”
template<> int bar<0>() { return 7; } ^:7:26: 注意:候选模板被忽略:无法匹配 'void ()' 反对 'int ()'
template<int N> void bar() {}; ^
Visual C++ 同意(MSVC 19 2017 RTW):
(8): 错误 C2912: 显式特化 'int Test::bar(void)' 不是函数模板的特化
gcc 8.2 不编译任何代码(尽管原因可能是bug in C++17 support:
:5:14: 错误:非命名空间范围内的显式特化 '类测试'
template<> auto foo<0>() { return 7; }; ^:5:28: 错误:主声明中的模板 ID 'foo' 模板
template<> auto foo<0>() { return 7; }; ^:7:26: 错误:模板参数列表过多
template<int N> void bar() {}; ^~~:8:14: 错误:非命名空间范围内的显式特化 '类测试'
template<> int bar<0>() { return 7; } ^:8:20: 错误:预期 ';'在成员声明的末尾
template<> int bar<0>() { return 7; } ^~~ ;:8:23: error: ' 之前的预期 unqualified-id
template<> int bar<0>() { return 7; } ^
这里的正确解释是什么?对于不同的方法特化,我可以有不同的返回类型吗(为什么只使用auto,而不是在明确指定它们时)?由于我对auto 和模板的了解有限,我会说“不”。我不明白为什么要使用 auto 而不是显式命名返回类型允许针对不同的专业有不同的返回类型。
但是,这些代码是我发现 elsewhere 的代码的简化版本,所以我的解释可能不正确 - 在这种情况下,我会很感激解释 为什么在 @ 时允许不同的返回类型987654344@ 用于特化,而明确命名类型似乎是被禁止的。
【问题讨论】:
-
@DanM。链接的问题与使用
auto和在专业化中明确命名返回类型之间的差异无关。 -
但确实如此。它引用了关于这个确切问题 AFAIU 的标准:eel.is/c++draft/dcl.spec.auto#11(这会导致编译器行为的差异)。您的示例还包含此错误:stackoverflow.com/questions/2097811/…
-
@DanM。据我了解,引用的草案说,当基本模板使用
auto时,应该使用auto进行专门化,而在专门使用具体类型的模板时,应该命名具体类型。据我所知,在这两种情况下更改专业化返回类型的问题上是沉默的。至于您评论的第二部分(链接stackoverflow.com/questions/2097811/c):我的代码与该问题中的代码不同,因为在我的代码类中Test不是模板,该问题有什么问题。 -
虽然 SO question 中的示例有一个模板类,但它同样适用于常规类。见stackoverflow.com/questions/5777236。虽然它应该适用于 c++17 及更高版本,但 GCC 仍然不支持它:gcc.gnu.org/bugzilla/show_bug.cgi?id=85282 该标准解释了为什么允许使用
foo。至于bar的错误——简单地将函数命名为与模板相同的方式并不意味着它是一种专业化。您只能专门化模板参数。int不是bar的模板参数(但你可以这样做,在这种情况下它应该可以工作)。