运算符+用于模板类的子类型

时间:2010-05-05 20:06:26

标签: c++ g++

我有一个定义子类型的模板类。我正在尝试将二进制operator+定义为模板函数,但编译器无法解析operator+的模板版本。

#include <iostream>
template<typename other_type> 
struct c {
  c(other_type v) : cs(v) {}
  struct subtype { subtype(other_type v) : val(v) {} other_type val; } cs;
};

template<typename other_type>
typename c<other_type>::subtype operator+(const typename c<other_type>::subtype& left,
                      const typename c<other_type>::subtype& right)
{ return typename c<other_type>::subtype(left.val + right.val); }

// This one works
// c<int>::subtype operator+(const c<int>::subtype& left,
//          const c<int>::subtype& right)
// { return c<int>::subtype(left.val + right.val); }

int main()
{
  c<int> c1 = 1;
  c<int> c2 = 2;
  c<int>::subtype cs3 = c1.cs + c2.cs;
  std::cerr << cs3.val << std::endl;
}

我认为原因是因为编译器(g ++ 4.3)无法猜测模板类型,因此它正在搜索operator+<int>而不是operator+

这是什么原因?你能提出什么样的优雅解决方案?

1 个答案:

答案 0 :(得分:4)

你的怀疑是正确的。编译器不知道other_type是什么。它无法从论证中推断出来。这种形式通常太松,无法提供所需的信息。考虑

template<typename other_type> 
struct c {
  c(other_type v) : cs(v) {}
  typedef int subtype;
};

如果您要传递int,那么c<T>中的任何一个都符合该法案,因为它们都具有int类型。在嵌套类的特定情况下,它可能是可能的,但即使这样它也不是唯一的。想象一下,在c<float>中你可以放typedef c<int> subtype;,那么c<float>::subtypec<int>::subtype都符合要求。

早在标准时间之前,就存在一个模板问题列表,特别是John Spicer确实经历过并发明了合理的解决方案。这是一个这样的问题,并且发现它不值得麻烦。你总是明确需要提供论证 - 它永远不会被推断出来。

您可以将代码更改为此

template<typename other_type> 
struct subtype { 
  subtype(other_type v) : val(v) {}
  other_type val; 
};

template<typename other_type> 
struct c {
  c(other_type v) : cs(v) {}
  subtype<other_type> cs;
};

template<typename other_type>
subtype<other_type> operator+(const subtype<other_type>& left,
                      const subtype<other_type>& right)
{ return subtype<other_type>(left.val + right.val); }

或者这个

template<typename other_type> 
struct c {
  c(other_type v) : cs(v) {}
  struct subtype { 
   subtype(other_type v) : val(v) {} other_type val; 

    /* note: don't forget friend! */
    friend subtype operator+(const subtype& left,
                      const subtype& right)
    { return subtype(left.val + right.val); }
  } cs;
};