This trick allows a member template to be called as a "copy ctor": but why?

Deleting the copy ctor with argument const volatile allows a member template to play the role of a copy ctor, but i am not sure why??

1
2
3
4
5
6
7
8
9
10
11
	class C
	{
	public:
		template<typename T>
		C(T const&)
		{
			std::cout << "Template copy constructor\n";
		}
		C() = default;
		C(C const volatile&) = delete;
	};


If we do not delete the copy ctor, the generated copy ctor is called instead of the member template. Quite unexpected!

if we delete the copy ctor receiving a const&, then the program does not call the member template

but, if we delete the copy ctor receiving a const volatile& as above then the member template is invoked "as if it were a copy ctor".... but why in this case and not in the others?


Thank you,
Juan
Short answer is two things:
1, a copy constructor is never a template: https://en.cppreference.com/w/cpp/language/copy_constructor
2. in overload resolution, non-template beats template https://en.cppreference.com/w/cpp/language/overload_resolution#Best_viable_function

If we do not delete the copy ctor, the generated copy ctor is called instead of the member template. Quite unexpected!

I guess you mean if you comment out line 10? You'll have a class with implicit copy constructor taking const C& and ordinary constructor taking const T&. Non-template beats template.

if we delete the copy ctor receiving a const&, then the program does not call the member template

I guess you mean if you remove the word 'volatile' from line 10? Tou have a class with copy constructor taking const C&, and ordinary constructor taking const T&. Non-template beats template, overload resolution picks the copy ctor, compilation fails because it's deleted.

if we delete the copy ctor receiving a const volatile& as above then the member template is invoked "

The class has a copy constructor taking const volatile C& and ordinary constructor taking const T&. If the argument is volatile, the copy ctor is chosen (and compilation fails). If the argument is non-volatile, the template ctor is chosen.
Last edited on
The thing is, marking a copy ctor deleted where that copy ctor receives a const volatile argument, allows the template member to be called because the copy ctor with non-volatile argment is not generated... this is what I don't understand.

This class never executes the template member but instead calls the generated copy ctor:

1
2
3
4
5
6
7
8
9
10
	class C
	{
	public:
		template<typename T>
		C(T const&)
		{
			std::cout << "Template 'copy' constructor\n";
		}
		C() = default;
	};


This class executes the template member when a copy ctor is needed because the copy ctor with volatile argument is marked deleted:


1
2
3
4
5
6
7
8
9
10
11
	class C
	{
	public:
		template<typename T>
		C(T const&)
		{
			std::cout << "Template copy constructor\n";
		}
		C() = default;
		C(C const volatile&) = delete;
	};


Finally, if we mark the copy ctor without volatile as deleted, then copy ctor is not called because it is deleted...but it does not call the member template either -> it causes a compilation error:



1
2
3
4
5
6
7
8
9
10
11
	class C
	{
	public:
		template<typename T>
		C(T const&)
		{
			std::cout << "Template copy constructor\n"; // NEVER CALLED!!
		}
		C() = default;
		C(C const &) = delete;
	};


Why is member template never called in this last case?

BTW: I took this from the book C++ Templates The Complete Guide by Josuttis
Last edited on
Why is member template never called in this last case?

because non-template beats template in overload resolution. It's a universal rule, not just for constructors: If you call f(x) and the choices are f(const X&) and template<class T>f(const T&), the best choice is f(const X&).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>

struct X{};

template<class T>
void f(const T&) {std::cout << __PRETTY_FUNCTION__ << '\n';}

void f(const X&) {std::cout << __PRETTY_FUNCTION__ << '\n';}

int main()
{
 f(X{}); // calls const X&
 f(7); // calls const T&   
}
Last edited on
Topic archived. No new replies allowed.