user2233706
user2233706

Reputation: 7227

Prevent templated copy constructor from being called

In the following, the templated copy constructor is being called.

#include <iostream>

using namespace std;

class A
{
public:
    A(){ cout << "Class A constructor\n";}
    A(const A &a){ cout << "Class A copy constructor\n"; }
};

class B : public A
{
public:
    B(){ cout << "Class B constructor\n";}
    B(const B &a){ cout << "Class B copy constructor\n"; }
};

template <typename T>
class Template
{
public:
    Template() { cout << "Template default\n"; }
    Template(const Template &a) { cout << "Template copy constructor\n"; }

    // This gets called
    template <typename T2>
    Template(const Template<T2> &a)
    {
        cout << "Templated template copy constructor\n";
    }

};

void funcT(const Template<A> &a)
{
}

int main()
{
    Template<B> bt;

    cout << "Calling funcT(bt)\n";
    funcT(bt);

    return 0;
}

How can I prevent the templated copy constructor from being called? I was expecting that since B is of type A, and I'm passing by reference, no constructor would not get called. I created a specialized copy constructor in hopes it would get called instead:

Template(const Template<A> &a)
{
    cout << "Specialized templated template copy constructor\n";
}

But that does not compile.

Basically, I don't want to call the existing three constructors when I call funcT().

Upvotes: 1

Views: 275

Answers (2)

Piotr Skotnicki
Piotr Skotnicki

Reputation: 48487

You can make your function a template that accepts any Template<T> but only when T inherits from A, so that no copies/conversions are made:

#include <type_traits>

template <typename T>
auto funcT(const Template<T>& a)
    -> typename std::enable_if<std::is_base_of<A, T>::value>::type
{
}

DEMO


We are not using C++0x

You can write your own enable_if and is_base_of:

template <bool b, typename T = void>
struct my_enable_if {};
template <typename T>
struct my_enable_if<true, T> { typedef T type; };
template <typename Base, typename Derived>
struct my_is_base_of
{
    static char test(Base*);    
    static long test(...);
    static const bool value = sizeof(test((Derived*)0)) == sizeof(char);
};

template <typename T>
typename my_enable_if<my_is_base_of<A, T>::value>::type funcT(const Template<T>& a)
{
}

C++98 DEMO

Upvotes: 2

robert
robert

Reputation: 161

Just because B derives from A does not mean Template<B> derives from Template<A>. Depending on what you're trying to accomplish a template function may work:

template<typename T>void funcT(const Template<T> &a)
{
}

./a.out
Template default
Calling funcT(bt)

Robert

Upvotes: 1

Related Questions