首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >引用类模板参数和常量表达式类成员的转换运算符

引用类模板参数和常量表达式类成员的转换运算符
EN

Stack Overflow用户
提问于 2019-06-09 18:42:23
回答 1查看 72关注 0票数 0
代码语言:javascript
复制
#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的一个成员。

在转换运算符的声明中使用

  1. rank

代码语言:javascript
复制
- g++ and clang compile without errors.
- MSVC 19.20 gives `unable to match definition to an existing declaration`

在转换运算符的声明中使用

  1. rank_

代码语言:javascript
复制
- 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?

  • What的
  1. 是这个问题的便携解决方案?

多亏了Artyer,将运算符定义中的符号名称从rank改为rank_解决了这个问题。这可能是由于名为rank的模板参数和类成员rank之间的歧义造成的。编译器以不同的方式执行名称查找。

Godbolt链接:https://godbolt.org/z/6oFdrf

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 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表达模板。

代码语言:javascript
复制
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,这允许您问题中的三个编译器接受代码。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56513902

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档