重载决议:分配空括号

M.M*_*M.M 8 c++ overload-resolution c++11

我写了一些代码S s;...... s = {};,期待它最终结果一样S s = {};.但事实并非如此.以下示例再现了该问题:

#include <iostream>

struct S
{
    S(): a(5) { }
    S(int t): a(t) {}

    S &operator=(int t)  { a = t; return *this; }
    S &operator=(S const &t) = default;

    int a;
};

int main()
{
    S s = {};

    S t;
    t = {};

    std::cout << s.a << '\n';
    std::cout << t.a << '\n';
}
Run Code Online (Sandbox Code Playgroud)

输出是:

5
0
Run Code Online (Sandbox Code Playgroud)

我的问题是:

  1. 为什么operator=(int)选择这里,而不是"模棱两可"或另一个?
  2. 是否有一个整洁的解决方法,没有改变S

我的意图是s = S{};.s = {};如果有效,写作会很方便.我目前正在使用s = decltype(s){};但是我宁愿避免重复类型或变量名称.

T.C*_*.C. 11

为什么operator=(int)选择这里,而不是"模棱两可"或另一个?

{}to int是身份转换([over.ics.list]/9).{}S是一个用户定义的转换([over.ics.list]/6)(在技术上,它是{}const S&,并且通过[over.ics.list]/8并进入[over.ics.ref]第一回来之前[ over.ics.list]/6).

第一场胜利.

有一个整洁的解决方法吗?

诀窍的变化std::experimental::optional使得t = {}总是变t空.关键是要制作operator=(int)一个模板.如果你想接受int,仅int,然后就变成

template<class Int, std::enable_if_t<std::is_same<Int, int>{}, int> = 0>
S& operator=(Int t) { a = t; return *this; }
Run Code Online (Sandbox Code Playgroud)

如果要启用转换,可以使用不同的约束(在这种情况下,您可能还希望通过引用获取参数).

关键是通过使右操作数的类型成为模板参数,您可以阻止t = {}使用此重载 - 因为它{}是一个非推导的上下文.

......没有改变S

是否template<class T> T default_constructed_instance_of(const T&) { return {}; }s = default_constructed_instance_of(s);算吗?