简体   繁体   English

模板友元 function 中的 C++17 和 C++20 与一元和二元运算符的区别

[英]Difference of C++17 and C++20 in template friend function with unary and binary operators

I have the following MWE in C++20 with clang++ -std=c++2a , in which I defined in-class unary - operator and friend -ed binary - operator:我在 C++20 中使用clang++ -std=c++2a有以下 MWE,我在其中定义了类内一元运算符和friend -二元运算符-

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;
}

However, this results in the following error in C++17:但是,这会导致 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&);
                        ^
                        ;

with Apple clang version 11.0.3 (clang-1103.0.32.59) .Apple clang version 11.0.3 (clang-1103.0.32.59)

The error disappears when I remove the in-class unary operator, or when I use C++20 via -std=c++2a .当我删除类内一元运算符或通过-std=c++2a使用 C++20 时,错误消失。

What is causing this issue in C++17, and how does C++20 resolves this issue? C++17 中出现此问题的原因是什么,C++20 如何解决此问题? Any help would be greatly appreciated!任何帮助将不胜感激!

This is due to the way name look-up proceeds inside class context.这是由于名称查找在 class 上下文中进行的方式。 Look up for names inside friend declarator are looked-up as in any member declarators.在朋友声明器中查找名称,就像在任何成员声明器中一样。 The pertinent lookup rules that apply here are:适用于此处的相关查找规则是:

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;在 [basic.lookup.unqual] 中列出的所有情况下,将按照每个相应类别中列出的顺序搜索范围以查找声明; name lookup ends as soon as a declaration is found for the name.一旦找到名称的声明,名称查找就会结束。 If no declaration is found, the program is ill-formed.如果没有找到声明,则程序格式错误。

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:在 X 的完整类上下文 ([class.mem]) 之外的 class X 的定义中使用的名称应以下列方式之一声明:

  • before its use in class X or be a member of a base class of X ([class.member.lookup]), or在用于 class X 之前或成为 X 的基础 class 的成员([class.member.lookup]),或
  • [...] [...]
  • 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. 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 class X 在命名空间 N 或 N 的封闭命名空间之一中。

Which means that:意思就是:

  1. names are first look up in the class scope, for member names;名称首先在 class scope 中查找成员名称;

  2. if this previous look up fails, name are looked up in the enclosing namespace scope.如果之前的查找失败,则在封闭的命名空间 scope 中查找名称。

When the compiler find the name operator- in the friend declaration it performs name look in the class context (incomplete).当编译器在友元声明中找到名称operator-时,它会在 class 上下文中执行名称查找(不完整)。 It finds the unary minus operator and stop there.它找到一元减号运算符并停在那里。

After that the compiler applies the following rule to determine if the name operator - can be a template name C++17/[temp.name]/3之后,编译器应用以下规则来确定名称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.在名称查找发现名称是模板名称或 operator-function-id 或literal-operator-id 引用一组重载函数后,其中任何成员都是 function 模板,如果后面跟着 < , < 总是作为模板参数列表的分隔符,而不是小于运算符。 [...] [...]

Lookup did not find any template, so inside the friend declaration operator - is not supposed to name a template. Lookup 没有找到任何模板,所以在friend 声明operator -不应该命名模板。 The compiler complains precisely at the < token that follows this name, which is not supposed to be there.编译器准确地在该名称后面的<标记处抱怨,该标记不应该存在。

A new C++20 rule makes the compiler more inclined to interpret that a name refers to template, C++20 standard/[temp.names]/2 :新的 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.如果名称查找找到包含 function 模板的模板名称或重载集,则认为名称引用模板。 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 .如果名称是后跟 < 的非限定 ID,则名称也被视为引用模板,并且名称查找找到一个或多个函数或什么也没找到

Name lookup in class vec scope find a function name and this name is followed by a < character, so this name refers to a template.在 class vec scope 中查找名称,找到一个 function 名称,该名称后跟一个<字符,因此该名称指的是模板。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如果无法编译未使用的函数,则模板类可以使用 C++17 编译,但不能使用 C++20 编译 - Template class compiles with C++17 but not with C++20 if unused function can't be compiled c++17 (c++20) 无序 map 和自定义分配器 - c++17 (c++20) unordered map and custom allocator operator==() 代码编译 w/C++17 但不编译 C++20 - operator==() code compiles w/C++17 but not C++20 为模板 class 专业化的构造函数/析构函数授予友谊 - 在 C++17 下工作,但在 C++20 下失败 - Granting friendship to constructor/destructor of template class specialization - works under C++17, but fails under C++20 在现代 C++11 / C++14 / C++17 和未来的 C++20 中枚举到字符串 - enum to string in modern C++11 / C++14 / C++17 and future C++20 什么是性病:: unary_function等价置换C ++ 17? - What is an equivalent replacement for std::unary_function in C++17? 为什么`std :: reference_wrapper`在c ++ 17中被弃用,而在c ++ 20中被删除? - Why is `std::reference_wrapper` deprecated in c++17 and removed in c++20? 为什么 rebind <U>::other 在 C++17 中被弃用并在 C++20 中被删除?</u> - Why rebind<U>::other are deprecated in C++17 and removed in C++20? 在 C++17 和 C++20 之间可移植地使用 UTF-8 字符串文字前缀 - Using UTF-8 string-literal prefixes portably between C++17 and C++20 在 C++17 / C++20 中从 wstring 转换为 u16string 并返回(符合标准) - Conversion from wstring to u16string and back (standard conform) in C++17 / C++20
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM