考虑我有这样的代码:
#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不兼容?
答案 0 :(得分:5)
因为初始化列表是非推断的上下文。来自[temp.deduct.type]:
未推断的背景是:
- [...]
- 一个函数参数,其关联参数是初始化列表(8.5.4),但参数 没有指定从初始化列表中扣除的类型(14.8.2.1)。 [例如:template<class T> void g(T); g({1,2,3}); // error: no argument deduced for T
-end example]
但是,在某些情况下,您仍然可以将初始化列表传递给模板。来自[temp.deduct.call]
模板参数推导是通过比较每个函数模板参数类型(称之为
P
)来完成的 调用的相应参数的类型(称之为A
),如下所述。如果P
是依赖类型, 从P
移除引用和 cv - 限定符会为std::initializer_list<P'>
提供P'[N]
或P'
N
并且参数是非空的初始化列表(8.5.4),然后对初始化列表的每个元素执行推导,将P'
作为函数模板参数类型和初始化元素如 它的参数,在P'[N]
的情况下,如果N
是非类型模板参数,则从初始化列表的长度推导出N
。
以下示例说明了这种情况的作用:
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上编译,但不正确。
答案 1 :(得分:1)
将模板版本更改为
template <typename ValueType>
void operator =(const std::initializer_list<ValueType> &) {}