为何C++模板类访问父模板类成员函数需命名限定符?
模板类继承std::vector时无法直接调用父类data()的原因
问题重现
尝试编写继承自std::vector的模板类Container存储自定义Data对象,代码如下:
#include<iostream> #include<vector> using namespace std; template <class T> class Data { T data; public: void print() { cout << data << endl; } }; template<class T> class Container : public std::vector<Data<T>> { public: void f() { cout << data() << endl; } }; int main() { Container<int> si; si.push_back(Data<int>()); return 0; }
编译时GCC报错:
<source>: In member function 'void Container<T>::f()': <source>:17:21: error: no matching function for call to 'data()' 17 | cout << data() << endl; | ~~~~^~ In file included from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/string:52, from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/locale_classes.h:40, from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/ios_base.h:41, from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/ios:42, from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/ostream:38, from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/iostream:39, from <source>:1: /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/range_access.h:311:5: note: candidate: 'template<class _Container> constexpr decltype (__cont.data()) std::data(_Container&)' 311 | data(_Container& __cont) noexcept(noexcept(__cont.data())) | ^~~~
修复方式
通过添加命名限定符明确指定调用基类的data()函数,修复后代码可正常编译:
template<class T> class Container : public std::vector<Data<T>> { using ContainerArray = std::vector<Data<T>>; public: void f() { cout << ContainerArray::data() << endl; } };
语法原因解析
这是C++模板两阶段编译和依赖名称查找规则导致的:
非模板类继承的情况:
当非模板类Normal继承std::vector<Data<int>>时,基类的类型是完全确定的,编译器在编译类定义时就能明确解析出基类的data()成员函数,因此直接调用data()不会有歧义。模板类继承的情况:
模板类Container继承的是std::vector<Data<T>>,其中T是模板参数,基类的具体类型要到模板实例化阶段(比如Container<int>被使用时)才能确定。在模板的定义阶段(实例化前),编译器不会去查找依赖于模板参数的基类成员——这类成员被称为依赖名称。
此时直接写data(),编译器会优先查找当前类作用域和全局作用域的名称,恰好全局作用域中存在std::data()这个自由函数(C++17引入的范围访问函数),它需要传入一个容器参数,但代码中没有传参,因此触发编译错误。为什么添加限定符能解决问题:
使用ContainerArray::data()或者this->data()的方式,相当于明确告诉编译器:这个data()是来自依赖于模板参数的基类成员,需要延迟到实例化阶段再去查找。当模板被实例化时,基类的具体类型已经确定,编译器就能正确找到std::vector的成员函数data()。
内容的提问来源于stack exchange,提问作者gongliming7
相关产品推荐
相关产品推荐

