1、问题
前段时间写了一段关于模板的代码,大概情形是这样的:
定义一个非模板类A
,有一个模板函数
,又定义了一个模板类B
,B中也定义了一个模板函数
。
将A作为B的模板参数进行实例化,在B的模板函数中调用A的模板函数。
在ubuntu18.04中编译(GCC 7.5.0)报错,尝试在ubuntu20.04
编译,依然报错。(在VS2015、VS2019编译都没问题,ubuntu16.04中的GCC 5.4.0也没问题)
2、问题分析
模板在实例化时,没有识别调用的A函数也模板函数,认为函数模板参数字符非法。
3、解决方法
需要使用template
关键字来显式标记模板成员函数。
即在类B的模板函数Get中,显式的标记模板函数a_instance.template Get<T>()
,而不是直接调用a_instance.Get<T>()
,见完整代码。
4、完整代码
完整代码如下:
#include <iostream>
#include <string>
// 类A的定义
class A {
public:
// 模板成员函数
template<typename T>
void Set(T value) {
std::cout << "A::Set called with value: " << value << std::endl;
}
// 模板成员函数,返回一个默认构造的T
template<typename T>
T Get() {
std::cout << "A::Get called, returning default-constructed T" << std::endl;
return T();
}
};
// 模板类B的定义
template<typename TA>
class B {
private:
TA a_instance; // A的实例作为B的成员
public:
// 模板成员函数
template<typename T>
void Set(T value)
{
std::cout << "B::Set called with value: " << value << std::endl;
a_instance.Set(value);
//a_instance.Set<T>(value);//在GCC 7.5.0 及以上版本编译失败
}
// 模板成员函数,返回一个默认构造的T
template<typename T>
T Get()
{
std::cout << "B::Get called, calling A::funcA and returning its result" << std::endl;
// 调用A的模板成员函数并返回其结果
return a_instance.template Get<T>();
//以下代码在GCC 7.5.0 及以上版本编译失败
//return a_instance.Get<T>();
}
};
int main() {
// 创建B<A>的对象,即B的模板参数为A
B<A> b;
int int_value = b.Get<int>();
std::string strSet = "set string";
b.Set<std::string>(strSet);
return 0;
}
在B::Set函数中,调用“a_instance.Set(value)”,不用显式的指定模板参数,因为A中Set接口通过入参,可以推导出模板类型,A中Get形参为空,因此不能推导出模板类型。