目前,我的一个玩具类模板有两个看起来非常相似的构造函数:
optional(const T& x)
{
construct(x);
}
optional(T&& x)
{
construct(std::move(x));
}
我可以将它们组合成一个构造函数模板,还是会以某种方式改变语义?
template<typename U>
optional(U&& x)
{
construct(std::forward<U>(x));
}
答案 0 :(得分:4)
模板化的构造函数永远不会(编译器认为是)复制构造函数,抱歉。
答案 1 :(得分:2)
它改变了std::is_constructible
和std::is_convertible
等特征与optional
互动的方式。例如:
class A {};
int main()
{
std::cout << std::is_constructible<optional<A>, int>::value << '\n';
};
您的原始代码会打印出来:
0
但是你的新代码会打印出来:
1
如果这是不受欢迎的,并且您仍希望使用新代码,则可以enable_if
将U
限制为可接受的类型。
我看到的唯一其他可能问题是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
类型的对象,我认为你应该没事......
U
类型的常量l值引用将绑定到construct(const T& x)
U
类型的非常量l值引用将绑定到construct(const T& x)
U
类型的临时r值将绑定到construct(T&& x)
或construct(const T& x)
U
类型的常量r值引用将绑定到construct(const T& x)