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

时间:2011-09-12 13:14:43

标签: c++ templates c++11 move-semantics perfect-forwarding

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

optional(const T& x)
{
    construct(x);
}

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

我可以将它们组合成一个构造函数模板,还是会以某种方式改变语义?

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

4 个答案:

答案 0 :(得分:4)

模板化的构造函数永远不会(编译器认为是)复制构造函数,抱歉。

答案 1 :(得分:2)

它改变了std::is_constructiblestd::is_convertible等特征与optional互动的方式。例如:

class A {};

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

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

0

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

1

如果这是不受欢迎的,并且您仍希望使用新代码,则可以enable_ifU限制为可接受的类型。

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

答案 2 :(得分:1)

  

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

然后可能语义不同。您的原始重载集会传递对const的左值引用或对非const的右值引用。模板版本也可以将左值引用传递给 -const。 (我忽略了对const的rvalue引用。)

尽管construct被声明为接受U&&,但是在T之前移动U const&之前的重载将无法正常工作,并且在这种情况下应该 em>处理非const左值,或者声明接受{{1}},在这种情况下它是无害的。

答案 3 :(得分:0)

假设您至少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)