【发布时间】:2020-08-08 07:04:34
【问题描述】:
我从C++ Templates the Complete Guide 书中得到了一段代码:
在下面的程序中,我们创建了一个带有完美转发模板构造函数的Person 类
和另外两个成员函数(const拷贝构造函数,移动构造函数)
#include <utility>
#include <string>
#include <iostream>
class Person
{
private:
std::string name;
public:
// generic constructor for passed initial name:
template<typename STR>
explicit Person(STR&& n) : name(std::forward<STR>(n)) {
std::cout << "TMPL-CONSTR for '" << name << "'\n";
}
// copy and move constructor:
Person (Person& p) : name(p.name) {
std::cout << "COPY-CONSTR Person '" << name << "'\n";
}
Person (Person const& p) : name(p.name) {
std::cout << "COPY-CONSTR Person '" << name << "'\n";
}
Person (Person&& p) : name(std::move(p.name)) {
std::cout << "MOVE-CONSTR Person '" << name << "'\n";
}
};
int main()
{
std::string s = "sname";
Person p1(s);
Person p2("tmp");
Person p3(p1); // Error
Person p4(std::move(p1));
}
关于Person p3(p1); 行的错误,这本书说“根据重载解决规则”
template<typename STR>
Person(STR&& n)
“比复制构造更好匹配”
Person(const Person& p)
所以,如果我在 Person 内部再添加一个构造函数,如下所示:
Person (Person& p) : name(p.name) {
std::cout << "COPY-CONSTR Person '" << name << "'\n";
}
错误应该消失。确实错误消失了,这是输出:
TMPL-CONSTR for 'sname'
TMPL-CONSTR for 'tmp'
COPY-CONSTR Person 'sname' : this is due to `Person (Person& p)`
MOVE-CONSTR Person 'sname'
但书上也说,这只是部分解决方案,因为 Person 的 Derived 类的模板构造函数仍然是重载决议规则的更好匹配。
所以我也试着检查一下:
#include <utility>
#include <string>
#include <iostream>
class Person
{
private:
std::string name;
public:
// generic constructor for passed initial name:
template<typename STR>
explicit Person(STR&& n) : name(std::forward<STR>(n)) {
std::cout << "TMPL-CONSTR for '" << name << "'\n";
}
// copy and move constructor:
Person (Person& p) : name(p.name) {
std::cout << "COPY-CONSTR Person '" << name << "'\n";
}
Person (Person const& p) : name(p.name) {
std::cout << "COPY-CONSTR Person '" << name << "'\n";
}
Person (Person&& p) : name(std::move(p.name)) {
std::cout << "MOVE-CONSTR Person '" << name << "'\n";
}
};
#if 1 // or 0
class newPerson : public Person
{
private:
std::string name;
public:
// generic constructor for passed initial name:
template<typename STR>
explicit newPerson(STR&& n) : name(std::forward<STR>(n)) {
std::cout << "TMPL-CONSTR for '" << name << "'\n";
}
// copy and move constructor:
newPerson (newPerson const& p) : name(p.name) {
std::cout << "COPY-CONSTR Person '" << name << "'\n";
}
newPerson (newPerson&& p) : name(std::move(p.name)) {
std::cout << "MOVE-CONSTR Person '" << name << "'\n";
}
};
#endif
int main()
{
std::string s = "sname";
Person p1(s);
Person p2("tmp");
Person p3(p1); // Error again
Person p4(std::move(p1));
}
在这种情况下我正在粘贴 clang 错误(gcc 错误列表太大)
specialmemtmplMain.cpp:41:5: error: constructor for 'newPerson' must explicitly initialize the base class 'Person' which does not have a default constructor
newPerson (newPerson const& p) : name(p.name) {
^
specialmemtmplMain.cpp:5:7: note: 'Person' declared here
class Person
^
specialmemtmplMain.cpp:44:5: error: constructor for 'newPerson' must explicitly initialize the base class 'Person' which does not have a default constructor
newPerson (newPerson&& p) : name(std::move(p.name)) {
^
specialmemtmplMain.cpp:5:7: note: 'Person' declared here
class Person
^
2 errors generated.
所以,我的问题是,我没有实例化任何 newPerson 类。那为什么错误是指newPerson构造函数?这里到底发生了什么?
【问题讨论】: