gpt4 book ai didi

c++ - C++17和C++20在模板友元函数中一元和二元运算符的区别

转载 作者:行者123 更新时间:2023-12-01 12:33:58 26 4
gpt4 key购买 nike

我在 C++20 中有以下 MWE 和 clang++ -std=c++2a ,其中我定义了类内的一元 -运算符和 friend -ed 二进制 -运算符(operator):

template<typename T>
class vec;

template<typename T>
vec<T> operator-(const vec<T>&, const vec<T>&);

template<typename T>
class vec {
public:
vec() {}
vec operator-() const { return vec(); }
friend vec operator-<>(const vec&, const vec&);
};

template<typename T>
vec<T> operator-(const vec<T>& lhs, const vec<T>& rhs) { return vec<T>(); }

int main()
{
vec<int> v;
return 0;
}

但是,这会导致 C++17 中出现以下错误:

main.cpp:12:16: error: friends can only be classes or functions
friend vec operator-<>(const vec&, const vec&);
^
main.cpp:12:25: error: expected ';' at end of declaration list
friend vec operator-<>(const vec&, const vec&);
^
;

Apple clang version 11.0.3 (clang-1103.0.32.59) .

当我删除类内一元运算符时,或者当我通过 -std=c++2a 使用 C++20 时,错误就会消失。 .

在 C++17 中是什么导致了这个问题,C++20 如何解决这个问题?
任何帮助将不胜感激!

最佳答案

这是由于名称查找在类上下文中进行的方式。在 friend 声明器中查找名称与在任何成员声明器中一样查找。适用于此处的相关查找规则是:

  • [basic.lookup.unqual]/1 :

  • In all the cases listed in [basic.lookup.unqual], the scopes are searched for a declaration in the order listed in each of the respective categories; name lookup ends as soon as a declaration is found for the name. If no declaration is found, the program is ill-formed.


  • [basic.lookup.unqual]/7 :

  • A name used in the definition of a class X outside of a complete-class context ([class.mem]) of X shall be declared in one of the following ways:

    • before its use in class X or be a member of a base class of X ([class.member.lookup]), or
    • [...]
    • if X is a member of namespace N, or is a nested class of a class that is a member of N, or is a local class or a nested class within a local class of a function that is a member of N, before the definition of class X in namespace N or in one of N's enclosing namespaces.


    意思就是:
  • 名称首先在类范围内查找,以获取成员名称;
  • 如果先前的查找失败,则在封闭的命名空间范围内查找名称。

  • 当编译器找到名称 operator-在友元声明中,它在类上下文中执行名称查找(不完整)。它找到一元减运算符并停在那里。

    之后,编译器应用以下规则来确定名称 operator -可以是模板名称 C++17/[temp.name]/3

    After name lookup finds that a name is a template-name or that an operator-function-id or a literal-operator-id refers to a set of overloaded functions any member of which is a function template, if this is followed by a <, the < is always taken as the delimiter of a template-argument-list and never as the less-than operator. [...]



    查找没有找到任何模板,所以在 friend 声明里面 operator -不应该命名模板。编译器正好在 < 处提示。跟在这个名字后面的 token ,它不应该在那里。

    新的 C++20 规则使编译器更倾向于解释名称是指模板, C++20 standard/[temp.names]/2 :

    A name is considered to refer to a template if name lookup finds a template-name or an overload set that contains a function template. A name is also considered to refer to a template if it is an unqualified-id followed by a < and name lookup either finds one or more functions or finds nothing.



    类中的名称查找 vec作用域找到一个函数名,这个名字后面跟着一个 <字符,所以这个名字指的是一个模板。

    关于c++ - C++17和C++20在模板友元函数中一元和二元运算符的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61642574/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com