【问题标题】:Error defining a templated operator overload定义模板化运算符重载时出错
【发布时间】:2014-06-12 22:17:24
【问题描述】:

这是一个尝试的 operator+ 的模板化重载。这无法同时使用 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;

【问题讨论】:

  • “编译失败”是否意味着您收到错误消息?错误信息是什么?
  • "couldn't deduce template parameter ‘U’" 对我来说似乎很清楚
  • 不相关,我不明白你为什么用两个模板参数编写版本,除非它们相同,否则它不会编译/工作。
  • 您认为U 是如何推导出来的?
  • 只是为了好玩:您可以实际上模拟返回类型的重载。请参阅实际编译的this example。将它推广到像a+(2*b)/c 这样的表达式更复杂(尽管并非不可能;)

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


【解决方案1】:

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

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,因此可以从函数模板参数中推导出来。

【讨论】:

  • 嗯,好的。我曾假设返回类型也将是扣除的一部分。谢谢!
  • 这在逻辑上是不可行的(一般情况下)。
【解决方案2】:

B<double> c = a+b;

类型模板参数U in

B<U> operator+(A<T> const& t, A<T> const& u)

无法推断。 U 不会被推断为double,因为调用的结果被分配给B&lt;double&gt;。您必须将U 明确指定为double,例如通过以下方式,

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&lt;U&gt;,其中U 可能与T 不同,所以也许正确的解决方案是使其能够构造B&lt;U&gt; 来自B&lt;T&gt;

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

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

【讨论】:

  • 这一行的第一行具有误导性。 B&lt;double&gt; = 实际上与它无关。
【解决方案3】:

编译器的错误信息很清楚。无法推导出参数U来实例化operator+函数。

你可以通过使用来明确:

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

【讨论】:

    【解决方案4】:

    不推导出返回类型。

    你可以用表达式模板来伪造它。

    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};
    }
    

    这应该会给你这个想法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-06
      • 2018-09-17
      • 2012-11-26
      • 2015-05-01
      • 1970-01-01
      相关资源
      最近更新 更多