xerion xerion - 2 months ago 16
C++ Question

Allow / Disable speicifc copy ctor and assignment operations for templates

I am wondering if it possible to achieve something with templates.
What I want to do is allow specific 'copy ctors and assigment operators' from one template to another and disable others.

I think I managed only one of the things that I want so I am providing the class below.
For copy ctors or assignment operators I want to be able to do the below


  • Foo<false>
    to
    Foo<false>
    always OK

  • Foo<true>
    should only be allowed to copied or assigned to
    Foo<false>



I am not sure if it is possible...

#include <iostream>
#include <type_traits>
using namespace std;

template<bool Owner>
class Foo
{
static constexpr bool owner_ = Owner;

public:
Foo() {std::cout << "ctor\n";}
Foo operator=(const Foo& foo) { std::cout << "assignment\n";}
Foo(const Foo& foo) { std::cout << "copy ctor \n"; }

template <bool U>
Foo( const Foo<U>& other)
{
std::cout << "copy ctor2 \n";
}

template <bool U>
Foo<false>& operator=( const Foo<U>& other)
{
std::cout << "assignment 2 \n";
return *this;
}

template < bool B_ = Owner, typename = std::enable_if_t <B_> >
void bar1() {
std:cout << "bar1 " << owner_ << "\n";
}

void bar2() {std:cout << "bar2 " << owner_ << "\n";}
};


At the moment the only thing that I have succeeded is that
operator=
will work for
Foo<false>
=
Foo<true>
.
Foo<false>
to
Foo<false>
is OK, but that allows all other conversions as well so
Foo<true>
to
Foo<true>
is possible.

Answer

Of course it's possible. Anything is possible in C++.

Your question wasn't 100% clear as to what is the expected behavior for all combinations, but this is easy enough to be trivially adjustable:

#include <iostream>

// Helper class

template<bool from, bool to> class ok_to_copy_foos;

// Define all valid conversions as specializations:

template<>
class ok_to_copy_foos<false, false> {

public:
    typedef bool type;
};

template<>
class ok_to_copy_foos<true, false> {

public:
    typedef bool type;
};

////////////////////////////////////////////////////////////////////

template<bool Owner>
class Foo {

public:

    Foo() {}

    template<bool U, typename allow=typename ok_to_copy_foos<U, Owner>::type>
    Foo(const Foo<U> &)
    {
        std::cout << "copy ctor \n";
    }

    template<bool U, typename allow=typename ok_to_copy_foos<U, Owner>::type>
    Foo &operator=(const Foo<U> &)
    {
        std::cout << "assignment\n";

        return *this;
    }
};

void foo()
{
    Foo<false> f1;
    Foo<true> t1;

    // These ones will compile:
    Foo<false> f2(f1);
    f2=f1;
    f2=t1;

    //   These ones will not compile
    //
    //      t1=f2;
    //  Foo<true> t2(f2);
}

EDIT: Looks like it is also be necessary to add an explicit copy constructor and an assignment operator. Deleting the default ones will not be sufficient:

Foo(const Foo &o)
{
    typename ok_to_copy_foos<Owner, Owner>::type dummy;
}

Foo &operator=(const Foo &o)
{
    typename ok_to_copy_foos<Owner, Owner>::type dummy;

    return *this;
}