Search code examples
c++class-templatecopy-assignment

make template class with std::vector<T> non-copyable when T is non-copyable


#include <vector>
#include <memory>

template<typename T>
class V {
public:
    template<typename U = T, std::enable_if_t<std::is_copy_assignable_v<U>, int> = 0>
    auto operator = (const V &rhs) -> V & { v = rhs.v; return *this; }
private:
    std::vector<T> v;
};

template<typename T>
class U {
public:
    template<typename U = T, std::enable_if_t<std::is_copy_assignable_v<U>, int> = 0>
    auto operator = (const U &rhs) -> U & { t = rhs.t; return *this; }
private:
    T t;
};

int main()
{
    static_assert(!std::is_copy_assignable_v<std::unique_ptr<int>>);    // success
    static_assert(!std::is_copy_assignable_v<U<std::unique_ptr<int>>>); // success
    static_assert(!std::is_copy_assignable_v<V<std::unique_ptr<int>>>); // fail
    return 0;
}

Here, U<T> and V<T> have assignment operator when T is copy-assignable.

However, static_assert to check if V<std::unique_ptr<int>> is non-copy-assignable fails although similar check for U<std::unique_ptr<int>> successes.

Why does the static_assert fail for V<T> here and how can I fix it?


Solution

  • The special copy assignment operator is never a template. In cpp insights we can see that the compiler will generate a non-template copy assignment operator in addition to the template operator you provided.

    You can conditionally disable special member functions of template class based on template parameter by inheriting from a base class with desired semantics

    #include <type_traits>
    
    class copyable { };
    class no_copy_assign { void operator=(const no_copy_assign&) = delete; };
    
    template<class T>
    class A :
        std::conditional_t</* Condition */, copyable, no_copy_assign>
    { };
    // Condition can be std::is_copy_assignable_v<T>