在与 initializer_list 不兼容的 C++ 模板复制赋值运算符中?

In C++ template copy assignment operator not compatible with initializer_list?

假设我有这样的代码:

#include <initializer_list>

class my_class
{
public:
    my_class() {}

    void operator = (const std::initializer_list<int>&) {} // OK
    template<typename ValueType> void operator = (const ValueType&) {} // Failed
};

int main(int argc, char* argv[])
{
    my_class instance;
    instance = {1, 2};

    return 0;
}

第一个复制赋值运算符可以通过 instance = {1, 2} 正常编译。但是,模板版本将失败并出现以下错误:

code.cpp:15:14: error: no viable overloaded '='
    instance = {1, 2};
    ~~~~~~~~ ^ ~~~~~~
code.cpp:3:7: note: candidate function (the implicit copy assignment operator) not viable: cannot convert initializer list argument to 'const my_class'
class my_class
      ^
code.cpp:3:7: note: candidate function (the implicit move assignment operator) not viable: cannot convert initializer list argument to 'my_class'
class my_class
      ^
code.cpp:9:39: note: candidate template ignored: couldn't infer template argument 'ValueType'
    template<typename ValueType> void operator = (const ValueType&) {}

为什么模板版本与 initializer_list 不兼容?

因为初始化列表是一个非推导的上下文。来自 [temp.deduct.type]:

The non-deduced contexts are:
— [...]
— A function parameter for which the associated argument is an initializer list (8.5.4) but the parameter does not have a type for which deduction from an initializer list is specified (14.8.2.1). [ Example:

template<class T> void g(T);
g({1,2,3}); // error: no argument deduced for T

—end example ]

但是,在某些情况下,您仍然可以将初始化列表传递给模板。来自 [temp.deduct.call]

Template argument deduction is done by comparing each function template parameter type (call it P) with the type of the corresponding argument of the call (call it A) as described below. If P is a dependent type, removing references and cv-qualifiers from P gives std::initializer_list<P'> or P'[N] for some P' and N and the argument is a non-empty initializer list (8.5.4), then deduction is performed instead for each element of the initializer list, taking P' as a function template parameter type and the initializer element as its argument, and in the P'[N] case, if N is a non-type template parameter, N is deduced from the length of the initializer list.

下面的示例说明了这种方法适用的情况:

template<class T> void f(std::initializer_list<T>);
f({1,2,3}); // T deduced to int

template<class T, int N> void h(T const(&)[N]);
h({1,2,3}); // T deduced to int, N deduced to 3

template<class T> void j(T const(&)[3]);
j({42}); // T deduced to int, array bound not considered

所以在你的具体情况下,你可以这样做:

template <typename T>
void operator=(std::initializer_list<T> ) { }

或:

template <typename T, size_t N>
void operator=(T const(&)[N]) { }

虽然后者显然不能在 clang 上编译,但错误。

将您的模板版本更改为

template <typename ValueType>
void operator =(const std::initializer_list<ValueType> &) {}