Search code examples
c++templatesconstructorcopy-constructor

Is there a difference between a copy constructor with an argument type of `const T &` and of type `const T<U> &`?


As of C++11, std::allocator defines three constructors that are roughly equivalent to those in the following class:

template<typename T>
class allocator {
public:
    constexpr allocator() noexcept = default;

    constexpr allocator(const allocator &other) noexcept = default;

    template<typename U>
    constexpr allocator(const allocator<U> &other) noexcept {};
};

The first is a default constructor, and the second is a copy constructor - pretty standard stuff. However, the third constructor confuses me quite a bit. It appears to technically be a specialization of the copy constructor? And if that is the case, would the second constructor ever even be called? Is = default required? How does the compiler know to provide a default implementation for the third constructor?


Solution

  • It [the third constructor] appears to technically be a specialization of the copy constructor?

    It is not a copy constructor at all. It is actually a converting constructor instead.

    would the second constructor ever even be called?

    If an allocator<T> object is used to construct another allocator<T> object, then the second constructor will be used, yes. For example:

    allocator<int> a1;
    allocator<int> a2(a1);
    

    But, if a different allocator<U> object is used to construct an allocator<T> object, where U is not the same type as T, then the third constructor will be used. For example:

    allocator<short> a1;
    allocator<int> a2(a1);
    

    Is = default required?

    Only if you want the compiler to auto-generate an implementation. Otherwise, you have to provide one yourself.

    How does the compiler know to provide a default implementation for the third constructor?

    Everything between {} in a constructor's body is user-defined. If there is no {} then you need to use = default (or = delete) instead.

    In a non-deleted constructor, the compiler always default-initializes each class member, unless specified otherwise in the constructor's member initialization list - which the 3rd constructor does not have.