c++ - 为什么模板化非常量参数构造函数优于给定的复制构造函数

标签 c++ c++17 variant requirements

我想让我的类能够在 std::variant 中使用。

应该工作的简单代码是:

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

    A a(1);
    v = a;
}

我的类包含一个模板化构造函数:

 template <typename T> A( T& );

这时麻烦就开始了!构造函数绑定(bind)到来自 std::variant 的调用,并且不再使用提供的 A(const A&)

出于复制和粘贴的原因,完整示例如下:

#include <iostream>
#include <variant>

class A
{
    private:
        int x;

    public:

        A( A&&) {}
        A( const A& ) {}
        A(){}
        ~A() {}

        A& operator=( const A& ) { return *this;}
        A& operator=( A&& ) {return *this;}

        template <typename T>
            A( T& t  ) 
            {
                std::cout << __PRETTY_FUNCTION__ << std::endl;
            }

        A(int _x):x{_x}{}
};

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

    A a(1);
    v = a;
}

背景:

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

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

最佳答案

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

template <typename T>
A(T& t)

这样的构造函数是有问题的,因为当参数是 A 类型的非 const 左值时,此构造函数优先于采用 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

并且可能会考虑使其显式

我们通常不提供采用非constA&的复制构造函数,因为它们与采用const A&的复制构造函数相比是多余的。

关于c++ - 为什么模板化非常量参数构造函数优于给定的复制构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52021074/

相关文章:

c++ - 从 std::string_view 删除字符串前缀的最佳方法?

c++ - std::variant 和 std::visit: 错误:没有名为 'valueless_by_exception' 的成员

c# - COM 方法调用在 C#、VB.NET 中失败,但在 Python 中有效

double 总和的 C++ 结果是错误的

c++ - 在 C++ 中检查变量类型

c++ - 创建具有多个继承输入类型的泛型类

c++ - 简明双向静态1 :1 mapping of values and types

在 OCaml 中打印变量类型

c++ - 关于派生类初始化中的基类

c++ - 将相同的 key (使用 malloc 创建)添加两次以映射