组合复制和移动的两个构造函数

combining two constructors that copy and move

本文关键字:两个 构造函数 复制 移动 组合      更新时间:2023-10-16

目前,我的一个玩具类模板有两个看起来非常相似的构造函数:

optional(const T& x)
{
    construct(x);
}
optional(T&& x)
{
    construct(std::move(x));
}

我可以将它们组合成一个单独的构造函数模板吗?或者这会以某种方式改变语义吗?

template<typename U>
optional(U&& x)
{
    construct(std::forward<U>(x));
}

模板化构造函数永远不会(被编译器认为是(复制构造函数,对不起。

它改变了std::is_constructiblestd::is_convertible等性状与optional相互作用的方式。例如:

class A {};
int main()
{
    std::cout << std::is_constructible<optional<A>, int>::value << 'n';
};

您的原始代码将打印出来:

0

但你的新代码会打印出来:

1

如果这是不可取的,并且您仍然希望使用新代码,您可以enable_if它来将U限制为可接受的类型。

我看到的唯一其他可能的问题是T是否可以是引用类型(例如int&(。在这种情况下,原始代码的第二个构造函数看起来很可疑,因为它将传递一个右值,并且您可能试图将该右值绑定到一个非常量左值引用(不能确定(。如果T永远不可能是引用类型,则无需担心这一点。

哦,construct不是构造函数,它是成员函数模板。

那么语义可能会有所不同。原始重载集将左值引用传递给常量,或将右值引用传递到非常量。模板版本还可以将左值引用传递给non-const。(我忽略了对常量的右值引用。(

尽管construct很可能被声明为接受U&&(否则你之前移动T的重载将不起作用(,并且在这种情况下应该处理非常值,或者被声明为接收U const&,在这种情况中它是无害的。

假设您至少定义了construct(const T& x),可能还定义了construct(T&& x)的加法,并且您的U类型的对象可以转换为T类型的对象,我认为您应该没事。。。

  1. U类型的常量l值引用将绑定到construct(const T& x)
  2. U类型的非常量l值引用将绑定到construct(const T& x)
  3. 如果未定义r值引用版本,则类型为U的临时r值将绑定到construct(T&& x)construct(const T& x)
  4. U类型的常量r值引用将绑定到construct(const T& x)