#include <cstddef>
template <class T, std::size_t rank_>
struct B { };
template <class T, std::size_t rank_>
struct A {
static constexpr auto rank = rank_;
operator B<T, rank>() noexcept;
};
template <class T, std::size_t rank>
A<T, rank>::operator B<T, rank>() noexcept { return {}; }
注意,rank_
是A
的一个类模板参数,rank
是一个编译时常量,它是A
的一个成员。
在转换运算符的声明中使用
rank
- g++ and clang compile without errors.
- MSVC 19.20 gives `unable to match definition to an existing declaration`
在转换运算符的声明中使用
rank_
- declaration is changed from `operator B<T, rank>() noexcept;` to `operator B<T, rank_>() noexcept;`
- g++ gives `no declaration matches A<T, rank>::operator B<T, rank>`
- clang gives `out-of-line definition of operator B<type-parameter-0-0, rank> does not match any declaration in A<T, rank_>`
- MSVC compiles without errors
谁是correct?
多亏了Artyer,将运算符定义中的符号名称从rank
改为rank_
解决了这个问题。这可能是由于名为rank
的模板参数和类成员rank
之间的歧义造成的。编译器以不同的方式执行名称查找。
Godbolt链接:https://godbolt.org/z/6oFdrf
发布于 2019-06-09 19:11:15
谁是正确的?
朗和GCC在所有方面都是正确的。更改后的定义变得病态的原因是一个有趣的子句混合。我会先给它们命名,然后再进一步解释。
temp.local
7在出现在类模板定义之外的类模板成员的定义中,类模板成员的名称会隐藏任何封闭类模板的模板参数的名称(但如果成员是类或函数模板,则不会隐藏成员的模板参数)。 示例:
模板struct A{ struct B{ /* ... */ };typedef void c;void f();模板void g(U);};模板void A::f() {B b;// A的B,不是模板参数}模板void A::g(C) {B b;// A的B,不是模板参数C C;//模板参数C,不是A的C}
- 结束示例
temp.over.link
4当在函数参数列表中使用引用模板参数的表达式或在函数模板的声明中使用返回类型时,引用模板参数的表达式是函数模板签名的一部分。这对于允许一个翻译单元中的函数模板的声明与另一个翻译单元中的函数模板的另一个声明相链接是必要的,并且相反地,为了确保意图不同的函数模板不彼此链接。 示例:
模板 A f(A,A);// #1模板 A f(A,A);//同#1模板 A f(A,A);//与#1不同
- 结束示例
因此,在opertor B<T, rank>
的声明中,id表达式rank
(A<T, rank_>::rank
)是运算符签名的一部分,因为它在返回类型中使用(转换运算符的返回类型是作为其名称的一部分隐式给出的),并且它引用了一个模板参数。
当您将operator B<T, rank>() noexcept;
更改为operator B<T, rank_>() noexcept;
时,您更改了操作符的签名!现在类外定义不匹配,因为假设类成员在::
之后隐藏了rank
参数,您仍然尝试在签名中使用id表达模板。
template <class T, std::size_t rank>
A<T, rank>::operator B<T, rank>() noexcept { return {}; }
// ^- This is the member of A, not the name
// of the parameter above it
这个问题的便携解决方案是什么?
不使用rank
成员作为模板参数或参数名,而是选择rank_
everywhere,这允许您问题中的三个编译器接受代码。
https://stackoverflow.com/questions/56513902
复制相似问题