tl; dr: 如果前面有template<typename Something>
,则不会调用复制构造函数,并且构造函数签名中使用Something
概念验证(ideone):
#include <cstdio>
template<typename T>
class Test {
private:
T value_;
public:
mutable bool has_copies;
Test(const T& value) : value_(value), has_copies(false) {}
template<typename Related> // remove template here to fix behavior
Test(const Test<Related>& t) {
printf("In copy constructor\n");
value_ = t.value_;
has_copies = true;
t.has_copies = true;
}
};
int main() {
Test<int> t1(42);
printf("Before constructor\n");
Test<int> t2(t1);
printf("After constructor:\n");
printf(" t1 thinks it %s copies\n", t1.has_copies ? "has" : "doesn't have");
printf(" t2 thinks it %s copies\n", t2.has_copies ? "has" : "doesn't have");
}
输出:
Before constructor
After constructor:
t1 thinks it doesn't have copies
t2 thinks it doesn't have copies
注意不打印In copy constructor
。
使复制构造函数非模板化(即删除template<typename Related>
并将Related
更改为签名中的T
)为我解决了这个问题。
$ g++ --version
g++ (GCC) 6.2.1 20160830
编译&amp;执行命令:
g++ -Wall -Wextra -pedantic -std=c++11 -O2 -Wshadow -Wformat=2 -Wfloat-equal -Wconversion -Wlogical-op -Wcast-qual -Wcast-align -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC -D_FORTIFY_SOURCE=2 -fsanitize=address -fsanitize=undefined -fno-sanitize-recover -fstack-protector "test.cpp" -o "test" && "test"
这里发生了什么?
答案 0 :(得分:5)
函数模板永远不能是复制构造函数,即使使用明显使其与复制构造函数的预期签名匹配的类型进行实例化也是如此。见[class.copy / 2]:
X类的非模板构造函数是一个复制构造函数,如果它的第一个参数是X&amp;类型,const X&amp;,volatile X&amp;或const volatile X&amp;,并且没有其他参数,或者所有其他参数都有默认参数。
所有类都有一个隐式生成的复制构造函数,如果没有用户声明的复制构造函数(有时可能被定义为已删除),则带有签名:
Test(Test const &) = default;
当您编写Test<int> t2(t1);
时,重载决策选择复制构造函数而不是模板函数,因为非模板优先于模板,所有其他条件相同。
请注意,如果您将模板函数更改为Test(Test<Related>& t)
,则现在将通过复制构造函数选择它:“所有其他内容”不再相等,并将模板实例化为与{{1}完全匹配添加Test<int>
以匹配复制构造函数的转换首选。
答案 1 :(得分:0)
T类的复制构造函数是非模板构造函数,其第一个参数是
while True: chunk = s.recv(10000) if not chunk: break fragments.append(chunk) print "".join(fragments)
,T&
,const T&
或volatile T&
,并且没有其他参数参数或其余参数都有默认值。
因此,构造函数作为模板失败,并且没有正确的参数类型。