为什么模板化的非const参数构造函数比给定的复制构造函数更可取

时间:2018-08-25 20:42:00

标签: c++ c++17 variant requirements

我想让我的班级可以在<table> <thead> {%- for column in columns %} <th>{{ column }}</th> {%- endfor %} </thead> <tbody> {%- for row in items %} <tr> {%- for column in columns %} <td>{{ row|attr(column) }}</td> {%- endfor %} </tr> {%- endfor %} </tbody> </table> 中使用。

应该起作用的简单代码是:

std::variant

我的课程包含模板化的构造函数:

int main()
{
    std::variant< int, A > v;

    A a(1);
    v = a;
}

这时麻烦就开始了!构造函数绑定到来自 template <typename T> A( T& ); 的调用,不再使用提供的std::variant

出于复制和粘贴的原因,此处为完整示例:

A(const A&)

背景:

为什么在这里使用模板? 使用使用序列化程序类型的构造函数时,问题开始。序列化器可以有多种类型,取决于要序列化的文件或流。

备注:我知道构造函数的功能缺失!

1 个答案:

答案 0 :(得分:3)

问题不在于std::variant。问题出在构造函数模板上,

template <typename T>
A(T& t)

这类构造函数有问题,因为当参数是类型为const的非A左值时,此构造函数优于采用const A&-的复制构造函数,通常不预期的行为。为了防止这种情况,我们通常用SFINAE约束此构造函数:

template <typename T, typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, A>>>
A(T& t)  // or T&& t

,也可以考虑将其设置为explicit

我们通常不提供采用非const A&的副本构造函数,因为在采用const A&的副本构造函数之后它们是多余的。