【发布时间】:2021-10-01 14:35:50
【问题描述】:
我试图在非肤浅的层面上理解为什么以下代码无法编译:
#include <vector>
template<typename T>
struct wrapper {
T wrapped_value;
wrapper() {}
template<typename... Args>
wrapper(Args&&... args) : wrapped_value( std::forward<Args>(args)... ) {
}
};
struct A {
int a;
A(int i = 0) : a(i) {
}
};
int main() {
std::vector<wrapper<A>> v1;
std::vector<wrapper<A>> v2;
v1 = v2;
}
我可以从std::vector 实现中的错误消息中看出,上述失败是因为wrapper<T> 的完美转发构造函数与复制构造函数匹配。通过替换到构造函数模板创建的复制构造函数将是
wrapper(wrapper<A>& w) : wrapped_value( w ) {
}
因为 wrapped_value 属于 A 类型,这是一个错误,因为 A 没有接受 wrapper<A> 的构造函数。
但是“替换失败不是错误”不是吗?因此,当编译器尝试将构造函数模板用作复制构造函数时,构造函数模板会失败——为什么这会阻止自动生成复制构造函数?还是不是,真正的问题与std::vector 的实现有关?
此外,这是一个玩具示例,但在处理此类类时,在我的真实代码中解决此类问题的最佳方法是什么?
- 使用“pass-by-value-then-move”而不是完美转发?
- 只需将复制构造函数定义为默认值?
- 在完美转发构造函数的可变参数之前使用 std::in_place_t 参数?
- 在通过
enable_if等进行复制构造的情况下禁用构造函数模板。等。
【问题讨论】:
-
SFINAE 是重载解决方案的一部分。一旦选择了重载并实例化了它的主体(是的,主体在实际调用之前没有实例化),就没有回溯。
-
所以这不是替换失败?是选择构造函数后报错?
-
看看 Meyers 的“Effective Modern C++”第 26-27 条,它几乎完全涵盖了你的情况。
标签: c++ constructor variadic-templates perfect-forwarding