强制编译器选择以 const T& 作为参数的复制构造函数

Force compiler to choose copy constructor with const T& as a parameter

本文关键字:参数 构造函数 复制 编译器 选择 const      更新时间:2023-10-16

我正在写一个类,我有一个模板化的构造函数和复制构造函数。每次我想用非const对象调用复制构造函数时,都会选择模板化构造函数。如何强制编译器选择复制构造函数?

#include <iostream>
struct foo
{
    foo()
    {
        std::cout << "def constructor is invokedn";
    }
    foo(const foo& other)
    {
        std::cout << "copy constructor is invokedn";
    }
    template <typename T>
    foo(T&& value)
    {
        std::cout << "templated constructor is invokedn";
    }
};
int main()
{
    foo first;
    foo second(first);
}

删除函数不是我想要的。

添加另一个构造函数:

foo(foo& other) : foo( const_cast<const foo&>(other))  // for non-const lvalues
{
}

示例代码中的first对象是非const左值,因此编译器更喜欢foo(foo&)而不是foo(const &)。前者由模板(含T=foo&)提供,因此选择

这个解决方案包括为foo(foo&)提供一个(非模板)构造函数,然后通过将其强制转换为对const的引用来将构造委托给复制构造函数。

更新,我刚刚意识到foo右值也将被模板采用。这里有很多选项,但我想最简单的是为foo(foo&&)添加一个委托,类似于上面的

foo(foo&& other) : foo( const_cast<const foo&>(other))  // for rvalues
{
}

问题是first是可变的,所以对它的引用是一个foo&,它比const foo&更容易绑定到通用引用T&&

大概,你打算T是任何非foo类?

在这种情况下,少量的enable_if欺骗向编译器表达了意图,而不必编写虚假的重载加载。

#include <iostream>
struct foo
{
    foo()
    {
        std::cout << "def constructor is invokedn";
    }
    foo(const foo& other)
    {
        std::cout << "copy constructor is invokedn";
    }
    template <typename T, std::enable_if_t<not std::is_base_of<foo, std::decay_t<T>>::value>* = nullptr>
    foo(T&& value)
    {
        std::cout << "templated constructor is invokedn";
    }
};
int main()
{
    foo first;
    foo second(first);
    foo(6);
}
预期输出:

def constructor is invoked
copy constructor is invoked
templated constructor is invoked