定义模板化运算符重载时出错

时间:2014-06-12 22:17:25

标签: c++ templates c++11 operator-overloading

这是运算符+的模拟重载尝试。这无法使用gcc 4.8和icc 14.0.3进行编译。

template <typename T>
class B
{
public:
  B operator+(const B& rhs)
  {
    return *this;
  }
};

template <typename T>
class A
{
public:
  operator B<T>() const{return B<T>();}
};

// template<typename T>                                                                                                                                                        
// B<T> operator+(A<T> const& t, A<T> const& u)                                                                                                                                
// {                                                                                                                                                                           
//   return (B<T>)t + (B<T>)u;                                                                                                                                                 
// }                                                                                                                                                                           

template<typename T, typename U>
B<U> operator+(A<T> const& t, A<T> const& u)
{
  return (B<U>)t + (B<U>)u;
}

int main()
{
  A<double> a,b;
  B<double> c = a+b;
  return 0;
}

然而,评论的重载工作正常。有什么不同?为什么带有两个参数的模板不匹配?

g++48 -std=c++11 temp2.cpp
temp2.cpp: In function ‘int main()’:
temp2.cpp:33:18: error: no match for ‘operator+’ (operand types are ‘A<double>’ and ‘A<double>’)
   B<double> c = a+b;
                  ^
temp2.cpp:33:18: note: candidate is:
temp2.cpp:25:6: note: template<class T, class U> B<U> operator+(const A<T>&, const A<T>&)
 B<U> operator+(A<T> const& t, A<T> const& u)
      ^
temp2.cpp:25:6: note:   template argument deduction/substitution failed:
temp2.cpp:33:19: note:   couldn't deduce template parameter ‘U’
   B<double> c = a+b;

4 个答案:

答案 0 :(得分:6)

编译器告诉你失败的原因:

  

temp2.​​cpp:25:6:注意:模板参数扣除/替换失败:
  temp2.​​cpp:33:19:注意:无法推断出模板参数'U'

模板参数U仅出现在函数模板的返回类型中,因此无法推断出。如果您明确列出模板参数

,您的代码将被编译
B<double> c = operator+<double, double>(a, b);

如果你交换模板参数的顺序,以便U出现在T之前,你仍然可以推导出T

template<typename U, typename T>
B<U> operator+(A<T> const& t, A<T> const& u)
{
  return (B<U>)t + (B<U>)u;
}

B<double> c = operator+<double>(a, b);

注释掉的operator+实现有效,因为返回类型也使用相同的类型参数T,因此允许从函数模板参数中推导出它。

答案 1 :(得分:5)

B<double> c = a+b;

中的类型模板参数U
B<U> operator+(A<T> const& t, A<T> const& u)

无法推断。 U不会仅仅因为呼叫结果已分配给double而被推断为B<double>。您必须明确指定Udouble,例如通过以下内容

B<double> c = operator+<double, double>(a, b);

现在显然这可能不是一个理想的情况。所以,你可以做什么?嗯,很难说,因为您还没有指定AB的用途。但是,正如您已经发现的那样,您的代码将使用已注释掉的运算符进行编译,

template<typename T>
B<T> operator+(A<T> const& t, A<T> const& u)
{
    return (B<T>)t + (B<T>)u;
}

出于某种原因,您似乎希望可以使用结果来初始化B<U>,其中U可能与T不同,所以也许正确的解决方案是可以从B<U>构建B<T>

template <typename T>
class B
{
public:
  template <typename U>
  B(const B<U>& rhs) {
    // ...
  }
  // ...
};

(您可能还想编写类似的赋值运算符。)

答案 2 :(得分:2)

编译器的错误消息很明确。它无法推导出参数U来实例化operator+函数。

您可以使用以下方式明确:

B<double> c = operator+<double, double>(a,b);

答案 3 :(得分:2)

不推断退货类型。

您可以使用表达式模板伪造它。

template<template<class>class Op, class Rhs, class Lhs>
struct deferred{
    Lhs lhs; Rhs rhs;
    template<typename Result>
    operator Result() const { return Op<Result>{}( std::forward<Lhs>(lhs), std::forward<Rhs>(rhs) ); }
};

template<class R> sum;
template<class U> sum<B<U>>{
  template<class Lhs, class Rhs>
  B<U> operator()( A<Lhs> const& lhs, A<Rhs> const& rhs )const{
    return B<Lhs>(lhs)+B<Rhs>(rhs);
  }
};
template<class T>
deferred<sum, A<T>const&, A<T>const&> operator+( A<T>const& a, A<T>const& b){
  return {a,b};
}

应该会给你一个想法。

相关问题