之前在说固定萃取的时候说过如下的例子:
templatestruct TraitsType; template<> struct TraitsType { using RetType = int; }; template<> struct TraitsType { using RetType = __int64; }; template auto GetSum(T* begin, T* end) { using retType = typename TraitsType ::RetType; cout << typeid(T).name() <<"==>"<< typeid(retType).name() << endl; retType sum{}; for (;;) { sum += (*begin); if (begin == end) { break; } begin++; } return sum; } int main() { int a1[] = { 1,3,5,7 }; int a2[] = { 500000000,500000000,700000000 }; char a3[] = "abc"; cout << GetSum(&a1[0], &a1[3]) << endl; cout << GetSum(&a2[0], &a2[2]) << endl; int nsum = (int)GetSum(&a3[0],&a3[2]); cout << nsum << endl; system("pause"); return 0; }
可以看到,求和的数组元素分别是int类型和char类型,其中char类型数据可以来看作范围比较窄的int类型数据,所以这两种类型数据都可以用RetType sum{};的形式进行零初始化,但如果数据组元素是其他类型的数据(如一个类类型),那么这种零初始化的格式可能就不合适。所以可以利用萃取技术解决这个问题,在说固定萃取的时候,核心思想是“传入一种类型,萃取出另外一种类型”,那么此处的值萃取的核心思想是“传入一种类型,萃取出一个值”。
将上面的代码修改为值萃取:
templatestruct TraitsType; template<> struct TraitsType { using RetType = int; static const RetType InitValue = 0; }; template<> struct TraitsType { using RetType = __int64; static const RetType InitValue = 0; }; template auto GetSum(T* begin, T* end) { using retType = typename TraitsType ::RetType; cout << typeid(T).name() << "==>" << typeid(retType).name() << endl; retType sum = TraitsType ::InitValue; for (;;) { sum += (*begin); if (begin == end) { break; } begin++; } return sum; }
虽然这种写法目前看不出问题,达式如果对一个元素类型为double的数组求和,就会出现问题,如下增加一个类模板的特化。
template<> struct TraitsType{ using RetType = double; static const RetType InitValue = 0.0; };
结果编译报错:
看上面的报错提示,只有整型才能这样初始化,浮点数不可以,但是使用c++11标准引入的constexpr关键字,发现是可以的,所以如下修改。
template<> struct TraitsType{ using RetType = double; static constexpr RetType InitValue = 0.0; };
结果一切正常,可以看到,通过值萃取类模板的手段,分别解决了数组元素为int、char、double时的求和问题,但是如果数组元素时类类型,如何进行类类型的求和呢?
class A
{
public:
A(int v1) :m_i(v1){}
int m_i;
A& operator+=(const A &obj)
{
m_i += obj.m_i;
return *this;
}
};
可以先做如下的尝试
template<> struct TraitsType { using RetType = A; static const RetType InitValue{0}; };
结果:
于是如下修改
template<> struct TraitsType { using RetType = A; static const RetType InitValue;//声明 }; const A TraitsType::InitValue = A{ 0 };//定义
最终解决问题,但是这种方式比较繁琐,在c++17中国,提出了一种新的解决方案解决类似的问题—inline变量,做如下修改:
template<> struct TraitsType { using RetType = A; inline static const RetType InitValue{0};//声明 };
先修改main:
int main()
{
A a1[] = { A{1},A{3},A{5},A{7} };
cout << GetSum(&a1[0], &a1[3]).m_i << endl;
system("pause");
return 0;
}
结果:



