compiler cares about copy constructor when it doesn't need one
Asked Answered
E

2

5

Why compiler cares about copy constructor when it doesn't need one?

#include <iostream>

template<typename T>
void print(T);

class Foo {
    Foo(const Foo&);
public:
    Foo(){}

};

template<>
void print(const Foo& f) {
    std::cout << "Foo\n";
}


int main(){
    Foo foo;
    print(foo);
}

function print is overloaded to accept const Foo& but compiler produces the following compilation error:

main.cpp: In function ‘int main()’:
main.cpp:21:14: error: ‘Foo::Foo(const Foo&)’ is private within this context
   21 |     print(foo);
      |              ^
main.cpp:7:5: note: declared private here
    7 |     Foo(const Foo&);
      |     ^~~
main.cpp:4:12: note:   initializing argument 1 of ‘void print(T) [with T = Foo]’
    4 | void print(T);
      |            ^

Why is it so? Obviously we don't need copy constructor, since we passing foo by reference and we have overload of print for that.

Ewer answered 30/9, 2019 at 16:37 Comment(3)
template<> void print(const Foo&) is not an overload, it's a specialization.Pronounce
Specializations (functions declared with template<>) don't participate in overload resolution.Pronounce
Specializations don't overload. Take out the template<>.Notice
S
4

Your specialization is not used in overload resolution. Overload resolution only synthesizes a signature from the primary template. The specialization is only used when calling the function, and only if the signature matches that which the compiler synthesized by itself. Since the primary takes an argument by value, this is the signature that participates in overload resolution:

void print(Foo); // T = Foo

And it doesn't match the signature you provided in the specialization (T = Foo const&), so the specialization isn't called. In fact, the only way to call your specialization, as is, is to specify the template argument explicitly:

print<Foo const&>(foo);

The way to proceed is not to specialize, but to overload. You can accomplish that by simply removing the template<> introducer. The regular overload participates in overload resolution, and will be chosen over the template generated one.

Surbeck answered 30/9, 2019 at 16:47 Comment(0)
N
3

The explicit specialization

template<>
void print(const Foo& f) {
    std::cout << "Foo\n";
}

requires to apply a qualification conversion.

So the primary template will be used instead of the specialization for the object

Foo foo;

You could explicitly specify the specialization

print<const Foo &>(foo);
Newson answered 30/9, 2019 at 16:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.