为何C++中被删除的成员函数不会在派生类中传递?
C++拷贝构造判定与标准规则疑问解答
代码示例
#include <type_traits> #include <iostream> template <typename T> struct Bar { Bar() = default; Bar(const Bar&) = delete; }; template <typename T> struct Foo : public Bar<T> { Foo() = default; Foo(const Foo& other) : Bar<T>(other) {} }; int main() { std::cout << std::is_copy_constructible_v<Bar<int>> << '\n'; // 输出0 std::cout << std::is_copy_constructible_v<Foo<int>> << '\n'; // 输出1 return 0; }
问题解答
1. 为何Foo被判定为可拷贝构造,但实际无法拷贝?
std::is_copy_constructible的判定仅聚焦于拷贝构造函数的声明是否合法,不会深入检查函数体内部的执行可行性。Foo显式声明了拷贝构造函数,这个声明本身符合语法要求;而基类Bar被删除的拷贝构造函数,只有在实际调用Foo的拷贝构造函数时,编译器才会去解析函数体里的基类构造调用,此时才会发现调用非法并报错。类型特性检查不会触及函数体内部的逻辑,所以会误判Foo为可拷贝构造。
2. 为何标准规定“仅考虑变量定义的直接上下文有效性”?
这个规定是为了平衡编译效率和元编程特性的确定性。如果类型特性检查需要深入函数体、依赖所有内部实现细节,会导致编译时间大幅增加,而且结果会变得不可预测——函数体可能依赖模板特化、外部类成员等大量不确定因素,这会让元编程逻辑变得混乱。限制在直接上下文(即声明层面),能让类型特性的结果快速、稳定,符合编译期元编程工具的设计目标。
3. 不清楚Foo实现的函数能否发现Foo无法拷贝?
仅通过std::is_copy_constructible这类类型特性检查,无法发现问题——它会得到Foo可拷贝的错误结论。只有当函数实际尝试拷贝Foo对象(比如执行Foo<int> a; Foo<int> b = a;这类代码)时,编译器才会进入拷贝构造函数的函数体检查,此时才会触发编译错误。
也就是说,若不实际执行拷贝操作,仅靠元编程判断会被误导;但只要触发拷贝动作,编译必然失败。
内容的提问来源于stack exchange,提问作者lobelk
相关产品推荐
相关产品推荐

