使用auto作为成员函数参数时的结果不同

Seo*_*oul 2 c++ c++14 c++17

运行这两个时,我得到了不同的结果

我在 GNU/Linux 4.14.67

这两者都使用g++ -std=c++14with/without -O0和on 运行c++17.

为什么我?为什么输出不同?

第一个版本是:

#include <iostream>
#include <algorithm>
using namespace std;

class foo {
public:
    foo() { }
    foo(const foo& f) { }
    foo& operator=(const foo& f) {
        cout << "foo operator=\n";
        val = 888;
        // Do something important
        return *this;
    }
    int val;
};

int main() {
    foo f1;
    foo f2;
    f1 = f2;

    cout << f1.val << endl;
}
Run Code Online (Sandbox Code Playgroud)

第一个输出是:

foo operator=
888
Run Code Online (Sandbox Code Playgroud)

第二个版本(仅const foo&改为const auto&):

#include <iostream>
#include <algorithm>
using namespace std;

class foo {
public:
    foo() { }
    foo(const foo& f) { }
    foo& operator=(const auto& f) {
        cout << "foo operator=\n";
        val = 888;
        // Do something important
        return *this;
    }
    int val;
};

int main() {
    foo f1;
    foo f2;
    f1 = f2;

    cout << f1.val << endl;
}
Run Code Online (Sandbox Code Playgroud)

第二个输出是:

0
Run Code Online (Sandbox Code Playgroud)

Bar*_*rry 5

这个:

foo& operator=(const auto& f);
Run Code Online (Sandbox Code Playgroud)

在C++ 20之前,它不会是标准的C++代码.但是gcc已经允许了很长一段时间,它意味着:

template <typename _T>
foo& operator=(const _T& f);
Run Code Online (Sandbox Code Playgroud)

换句话说,这是一个赋值运算符模板.它不是复制赋值运算符.那必须是非模板.由于您没有提供复制赋值运算符,编译器很乐意为您生成一个.在您的第一个代码示例中,您提供了自己的复制赋值运算符.

当你写:

f1 = f2;
Run Code Online (Sandbox Code Playgroud)

在第一个示例中,该表达式有一个候选项:您编写的复制赋值运算符.在第二个示例中,有两个候选项:赋值运算符模板和编译器合成的复制赋值运算符.编译器是一个更好的匹配(非模板节拍模板),因此它被调用 - 而不是你的.