类类型名匹配时如何引入基模板类类型到当前作用域?(GCC编译报错)
GCC特有的
value_type含义冲突编译错误解决方案 问题背景
开发统计数据管理软件时,写了一套基于模板和宏的统计类定义代码,用clang++ -std=c++17可以正常编译,但用g++ -std=c++17编译时触发错误:
using.cpp:15:49: error: declaration of ‘using statistic<T>::value_type’ changes meaning of ‘value_type’ [-Wchanges-meaning]
根源是在vec<T>类内部调用STAT(mult_by_2, value_type)时,宏展开后,statistic<value_type>::value_type里的第一个value_type是vec<T>的类型别名,而原宏里的using typename statistic<TYPE>::value_type;是把基类的value_type引入当前作用域,GCC认为这修改了value_type的含义,因此报错。
解决方案
方案1:修改宏的类型引入方式(最简便)
把宏里的继承引入声明改成显式类型别名声明,明确在内部类作用域定义value_type,让GCC明白这是主动定义别名而非修改已有含义:
#define STAT(NAME, TYPE) \ class NAME##_impl: public statistic<TYPE> { \ public: \ // 替换原语句为显式别名定义 using value_type = typename statistic<TYPE>::value_type; \ \ value_type f(int param) override; \ } NAME; \
修改后,内部类的value_type被明确绑定到基类的对应类型,GCC不会再触发冲突错误,原有的成员函数定义也不需要改动。
方案2:移除多余的类型引入
如果不需要在内部类作用域显式暴露value_type,可以直接删掉宏里的using typename statistic<TYPE>::value_type;行,改为在成员函数中直接指定基类类型:
#define STAT(NAME, TYPE) \ class NAME##_impl: public statistic<TYPE> { \ public: \ typename statistic<TYPE>::value_type f(int param) override; \ } NAME; \
对应的成员函数定义也要调整为明确引用基类类型:
template<class T> typename vec<T>::mult_by_2_impl::value_type vec<T>::mult_by_2_impl::f(int param) { typename statistic<typename vec<T>::value_type>::value_type var = 2*param; return var; }
方案3:用C++17自动返回值推导简化代码
利用C++17支持的返回值自动推导特性,把成员函数的实现直接写到宏里,绕开类型别名的冲突问题:
#define STAT(NAME, TYPE) \ class NAME##_impl: public statistic<TYPE> { \ public: \ auto f(int param) override { \ typename statistic<TYPE>::value_type var = 2 * param; return var; } \ } NAME; \
这种方式不需要在类外部单独定义成员函数,代码更紧凑,同时避免了类型名冲突的问题。
内容的提问来源于stack exchange,提问作者Vladyslav Rehan
相关产品推荐
相关产品推荐

