明确删除赋值运算符时允许从右值赋值?

Assignment from rvalue allowed when assignment operator explicitly deleted?

考虑以下代码,它在 Clang、GCC 和 VS 2015 (online example) 下编译:

#include <utility>

class S 
{
public:
    S(int x) : i(x) { }
    ~S() { }

    S(S&&)  = default;

    S(const S& )            = delete;
    S& operator=(S&&)       = delete;
    S& operator=(const S&)  = delete;

private:
    int i;
};

S GetS() 
{ 
    // This is a contrived example with details elided. Assume 
    // there's a reason in the actual use case for returning via 
    // std::move.
    return std::move( S(999) ); 
}

int main()
{
    S tmp = GetS(); // <-- Assignment allowed even though assignment operator is deleted?

    return 1;
}

我不清楚为什么这条线

S tmp = GetS(); 

编译,执行移动构造函数而不是移动赋值运算符。

我知道 RVO 允许省略构造和赋值作为优化,但据我了解,如果在代码中显式使用该运算符,则显式删除该运算符会导致编译失败。

C++11 规范中是否有某些子句允许编译器将赋值初始化转换为复制构造,即使类型的赋值运算符已被显式删除?

那是因为这不是作业:

S tmp = GetS(); 

它被称为 copy-initialization 并调用您已明确默认的移动构造函数。

基本上,赋值运算符仅在已存在的对象上调用。 tmp 还不存在,这条语句初始化它。因此,您正在调用构造函数。

请注意,GetS() 内部 发生的事情不会影响 tmp 的构建规则。 GetS() 无论如何都是右值。