Reputation: 263220
Currently, one of my toy class templates has two constructors that look very similar:
optional(const T& x)
{
construct(x);
}
optional(T&& x)
{
construct(std::move(x));
}
Can I combine them into a single constructor template, or will this change the semantics somehow?
template<typename U>
optional(U&& x)
{
construct(std::forward<U>(x));
}
Upvotes: 8
Views: 1146
Reputation: 145359
A templated constructor will never be (considered by the compiler to be) a copy constructor, sorry.
Upvotes: 5
Reputation: 32530
Assuming you have at least construct(const T& x)
and possibly the addition of construct(T&& x)
defined, and your object of type U
is convertable to an object of type T
, I think you should be fine ...
U
will bind to construct(const T& x)
U
will bind to construct(const T& x)
U
will bind to construct(T&& x)
or construct(const T& x)
if the r-value reference version is not definedU
will bind to construct(const T& x)
Upvotes: 0
Reputation: 219205
It changes the way traits such as std::is_constructible
and std::is_convertible
interact with optional
. For example given:
class A {};
int main()
{
std::cout << std::is_constructible<optional<A>, int>::value << '\n';
};
Your original code would print out:
0
But your new code will print out:
1
If this is undesirable, and you still want to go with your new code, you could enable_if
it to restrict U
to acceptable types.
The only other possible issue I see is if T
can be a reference type (e.g. int&
). In that case the second constructor of your original code looks suspicious as it would be passing in an rvalue, and you might be trying to bind that rvalue to a non-const lvalue reference (can't tell for sure). If T
can never be a reference type, no need to worry about this.
Upvotes: 2
Reputation: 35449
Oh, construct is not a constructor, it's member function template.
Then possibly the semantics are different. Your original overload set passes either an lvalue reference to const or an rvalue reference to non-const. The template version can pass an lvalue reference to non-const as well. (I'm ignoring rvalue references to const.)
In all likeliness though construct
is either declared to accept U&&
(else your previous overload that moves a T
wouldn't work) and in this case should deal with non-const lvalues, or is declared to accept U const&
and in this case it's harmless.
Upvotes: 1