5
votes

I'm trying to create a class which is copyable dependent on its template parameter (bool Copyable) otherwise it is move only.

It shall be constructible from the type itself (default constructor) through myclass(myclass&&) and myclass(myclass const&) when enabled through the template parameter bool Copyable.

Also it shall be constructible from myclass with other template arguments, which is covered by my current implementation through the templated constructors and assignment operators.

The rule of zero is used here to generate the default constructors and assignment operators through the inherited copyable helper struct which disables the copy constructor and copy assignment operator when bool Copyable is false.

template<bool>
struct copyable { };

template <>
struct copyable<false>
{
    // Disables copy construct & copy assign
    copyable() = default;
    copyable(copyable const&) = delete;
    copyable(copyable&&) = default;
    copyable& operator=(copyable const&) = delete;
    copyable& operator=(copyable&&) = default;
};

template<typename A, typename B, typename C>
struct storage_t
{
    // Implementation depends on A, B and C
};

template<typename A, typename B, typename C, bool Copyable>
class myclass
    : public copyable<Copyable>
{
    storage_t<A, B, C> _storage;

public:
    // It should generate the default constructors and
    // assignment operatos dependent on its inherited helper struct copyable.

    // Comment this out to disable the error...
    // (Implementation omitted)
    template<typename A, typename B, typename C>
    myclass(myclass<A, B, C, true> const&) { }

    template<typename A, typename B, typename C, bool Copyable>
    myclass(myclass<A, B, C, Copyable>&&) { }

    template<typename A, typename B, typename C>
    myclass& operator= (myclass<A, B, C, true> const&) { return *this; }

    template<typename A, typename B, typename C, bool Copyable>
    myclass& operator= (myclass<A, B, C, Copyable>&&) { return *this; }
    // ... comment end
};

By interpreting earlier answers at stackoverflow like:

Which says:

The compiler will still generates a default copy-constructor for you, instead of instantiating the templated constructor.

I thought that the compiler still generates a default constrctor although there is a templated constructor provided.

But the compilation of the upper example code fails with the error message (msvc 2015):

error C2512: 'myclass': no appropriate default constructor available:

myclass<int, int, int, true> mc1;

When i outcomment the provided templated constructors and assignment operators the default constructors are used but the capability is lost to assign a myclass with other template parameters.

A simple usage example would be:

/////
// Testing the copyable class
myclass<int, int, int, true> mc1;

// Copy construct
myclass<int, int, int, true> mc2(mc1);
// Copy assign
mc1 = mc2;

/////
// Testing the move only class
myclass<int, int, int, false> mc3;

// Move construct
myclass<int, int, int, false> mc4(std::move(mc3));
// Move assign
mc3 = std::move(mc4);

// Not working part:
// Copy and move from myclass with other template params
myclass<int, int, float, true> mc5;
// Error here:
mc1 = mc5;

Is there a way to disable the copy construct and assignment operators as described through a template parameter and also provide templated constructors/assignment operators?

1
default constructor is not generated if you provide others constructor, just provide myclass(const myclass&) = default;.Jarod42
Your templated "copy constructor" is not really a copy constructor AFAIK. Copy constructors are only those that take as first argument the same exact class type as it has been instanciated.Shoe
@Jarod42 When i'm declaring the copy constructor as default it gets accessible to myclass with Copyable = false.Denis Blank
@DenisBlank: I talked about default constructor (but provide bad code, I meant myclass() = default).Jarod42
@Jarod42 Alright it works, could you create an answer for this which i could accept?Denis Blank

1 Answers

2
votes

Default constructor is not generated if you provide other constructors.

Just provide a default one:

myclass() = default;

In your case, copy constructor is still generated if possible (which is not the case, when you inherit of copyable<false>).