C++模板复制分配运算符与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不兼容?

因为初始值设定项列表是一个非推导的上下文。从 [温度扣除类型]:

非推导上下文是:
— [...]
— 一个函数参数,其关联参数是初始值设定项列表 (8.5.4(,但参数 没有指定从初始值设定项列表中扣除的类型 (14.8.2.1(。[ 示例:

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

—结束示例 ]

但是,在某些情况下,您仍然可以将初始值设定项列表传递给模板。从 [温度扣除调用]

模板参数

推导是通过比较每个函数模板参数类型(称为 P (来完成的 调用的相应参数的类型(调用它A(,如下所述。如果P是依赖类型, 从P中删除引用和 CV 限定符会为某些P'提供std::initializer_list<P'>P'[N] 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]) { }

尽管后者显然不会在叮当声上编译,但不正确。

将模板版本更改为

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

相关内容

最新更新