Компилятор заботится о конструкторе копирования, когда он не нужен - PullRequest
5 голосов
/ 30 сентября 2019

Почему компилятор заботится о конструкторе копирования, когда он не нужен?

#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);
}

Функция print перегружена для приема const Foo&, но компилятор выдает следующую ошибку компиляции:

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);
      |            ^

Почему это так? Очевидно, нам не нужен конструктор копирования, так как мы передаем foo по ссылке, и у нас есть перегрузка print для этого.

Ответы [ 2 ]

4 голосов
/ 30 сентября 2019

Ваша специализация не используется в разрешении перегрузки. Разрешение перегрузки синтезирует только сигнатуру из шаблона primary . Специализация используется только тогда, когда вызывает функцию, и только если сигнатура совпадает с сигнатурой, которую компилятор сам синтезировал. Поскольку первичный параметр принимает аргумент по значению, это сигнатура, которая участвует в разрешении перегрузки:

void print(Foo); // T = Foo

И она не соответствует подписи, которую вы указали в специализации (T = Foo const&), поэтому специализацияне называется. Фактически, единственный способ вызвать вашу специализацию, как есть, - это явно указать аргумент шаблона:

print<Foo const&>(foo);

Чтобы продолжить, нужно не специализироваться, а перегрузить. Это можно сделать, просто удалив интродьюсер template<>. Обычная перегрузка участвует в разрешении перегрузки и будет выбираться из сгенерированного шаблона.

3 голосов
/ 30 сентября 2019

Явная специализация

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

требует применения преобразования квалификации.

Таким образом, вместо специализации для объекта будет использоваться основной шаблон

Foo foo;

Вы можете явно указать специализацию

print<const Foo &>(foo);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...