Templated copy constructor

How can I make a class use a template copy constructer over the compiler generated default copy constructor?

1
2
3
4
5
6
7
8
struct test
{
    test() = default;

    template<typename T>
    test(const T&) { std::cout << "TEMPLATE" << std::endl;}
    //This one is never called when a copy is made and compiler still generates default, which is the one that is called when a copy is made
};
Last edited on
This is tricky and not so obvious to achieve. If you try to do it this way:
1
2
3
4
5
6
7
8
struct test
{
    test() = default;
    test(test const&) = delete; //ERROR

    template<typename T>
    test(const T&) { std::cout << "TEMPLATE" << std::endl;}
};


The compiler still uses the explicitly deleted copy ctor for overload purposes. When you attempt to copy something now, it will complain saying you are using a deleted method, since the deleted "definition" is a better match than your template. Basically your templated special member functions will never be considered. There is a trick to get around this:

1
2
3
4
5
6
7
8
struct test
{
    test() = default;
    test(test const volatile&) = delete; //No error

    template<typename T>
    test(const T&) { std::cout << "TEMPLATE" << std::endl;} //Works
}; 


Make it volatile. Then, the compiler will search for a better match and finds that the template is a better match than the volatile copy ctor for non volatile objects, and it will use your template.
So, what you want is a templated copy constructor in a non-templated class (struct)?
May I ask you what you’re trying to achieve? Maybe there are better ways…
@TheToaster
Holy shit thank you! That actually worked! I have no idea how volatile fixes the problem here though. Could you explain why that is?

@Enoizat
This is not the original code. I simplified the problem I'm facing so people would understand better. My original class is a template itself.

Basically, my original code has the class as a template and it has a few template parameters. I want to be able to assign templates with different template parameters to each other:

test<int, 6> a = test<double, 9>{};

I want my template copy constructor to always be used, and I do NOT want the compiler to generate a default copy constructor for types that are the same. I couldn't do it because when I made the copy constructor a template, then when the two types are the same, that constructor isn't even considered and the compiler continues to generate a default.
Last edited on
When you use the copy constructor, the compiler will see that the object being copied is not volatile. Thus, it will look for a better match (overload resolution rules) and if there isn't a better match for the copy constructor, it will resort to using the deleted volatile copy constructor as as last resort (which will make the compiler complain due to the use of a deleted function).

In this case, a better match IS found, and that match is the templated copy constructor that is not marked as volatile, so the compiler doesn't use the deleted method. Since you have provided a definition for a copy constructor (you defined one with "delete"), the compiler will not generate its own copy constructor.
Last edited on
I still don't see why this code is an error:
1
2
3
4
5
6
7
8
struct test
{
    test() = default;
    test(test const&) = delete; //ERROR

    template<typename T>
    test(const T&) { std::cout << "TEMPLATE" << std::endl;}
};


If I say it as delete, then the compiler doesn't generate a copy constructor right? It should just be deleted and the it should look at my template one and use it. Doesn't delete tell the compiler to not make a default copy constructor?

Why does marking it volatile change anything?
Last edited on
Topic archived. No new replies allowed.