5

为什么编译器在不需要复制构造函数时会关心它?

#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

4

2 回答 2

4

您的专业化不用于重载决议。重载解析仅从模板合成签名。特化仅在调用函数时使用,并且仅当签名与编译器自己合成的签名匹配时才使用。由于主节点按值接受参数,因此这是参与重载决议的签名:

void print(Foo); // T = Foo

并且它与您在专业化 ( ) 中提供的签名不匹配T = Foo const&,因此不会调用专业化。事实上,调用你的特化的唯一方法是显式指定模板参数:

print<Foo const&>(foo);

前进的方法不是专门化,而是超载。您可以通过简单地移除template<>介绍人来实现这一点。常规重载参与重载决议,并将在模板生成的重载中被选择。

于 2019-09-30T16:47:53.723 回答
3

显式专业化

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

需要申请资格转换。

因此将使用主模板而不是对象的特化

Foo foo;

您可以明确指定专业化

print<const Foo &>(foo);
于 2019-09-30T16:45:27.183 回答