Search code examples
c++templatesc++11move-semanticsperfect-forwarding

combining two constructors that copy and move


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));
}

Solution

  • 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.