运算符中的模板参数推导/替换

时间:2016-08-12 17:21:15

标签: c++ templates gcc operator-overloading

我有一组派生自一个基类的类:

template<typename Traits>
class Base{
  typedef typename Traits::scalar_t scalar_t;
public:
  virtual ~Base(){}
  virtual scalar_t apply(const scalar_t&) const=0;
};

template<typename Traits>
class Pover_of_Number:
public Base<Traits>{
  typedef typename Traits::scalar_t scalar_t;
public:
  Pover_of_Number(const scalar_t& power):
  power(power){}
  scalar_t apply(const scalar_t& value) const override{
    return pow(value,power);
  }
private:
  scalar_t power;
};

template<typename Traits>
class Mult_by_Number:
public Base<Traits>{
  typedef typename Traits::scalar_t scalar_t;
public:
  Mult_by_Number(const scalar_t& num):
  num(num){}

  scalar_t apply(const scalar_t& value) const override{
    return num*value;
  }
private:
  scalar_t num;
};

template<typename Traits>
class SumOperator:
public Base<Traits>{
  typedef Base<Traits> BT;
  typedef typename Traits::scalar_t scalar_t;
public:
  SumOperator(const std::shared_ptr<Base<Traits>>& op1,
              const std::shared_ptr<Base<Traits>>& op2):
  op1{op1}, op2{op2}{}

  scalar_t apply(const scalar_t& value) const override{
    return op1->apply(value)+op2->apply(value);
  }
private:
  std::shared_ptr<BT> op1;
  std::shared_ptr<BT> op2;
};

对于某些特定的Traits,此代码可以完美运行:

class TraitsExample{
public:
  typedef double scalar_t;
};

int main(){
  auto op1=std::make_shared<Pover_of_Number<TraitsExample>>(2.);
  auto op2=std::make_shared<Mult_by_Number<TraitsExample>>(10.);

  //works correctly
  auto sumop=std::make_shared<SumOperator<TraitsExample>>(op1,op2);
  std::cout<<sumop->apply(2.)<<std::endl;

现在我想重载使用我的派生类(3 = 1 + 2)的operator+

template<typename Traits>
std::shared_ptr<SumOperator<Traits>> operator+(
  const std::shared_ptr<Base<Traits>>& op1,
  const std::shared_ptr<Base<Traits>>& op2){
  return std::make_shared<SumOperator<Traits>>(op1,op2);
}

但是当我在代码中使用它时出现template argument deduction/substitution failed错误。

有人可以向我解释为了让gcc编译我的代码需要做些什么,最好不要使用任何额外的类来进行演绎。

PS:人们可以找到工作example。正如我所说,我还需要重载+运算符。

1 个答案:

答案 0 :(得分:0)

此处的问题是编译器无法推断Traits尝试将参数类型std::shared_ptr<Pover_of_Number<TraitsExample>>与参数类型std::shared_ptr<Base<Traits>>匹配。从第一个转换为std::shared_ptr<Base<TraitsExample>>涉及隐式转换,因此扣除不会自动发生。

我会在您的typedef课程中添加公开Base<Traits>并使用它来确定operator+的返回类型应该是什么:

#include <type_traits>

template<typename Traits>
class Base{
  typedef typename Traits::scalar_t scalar_t;
public:
  using traits_type = Traits;
  virtual ~Base(){}
  virtual scalar_t apply(const scalar_t&) const=0;
};

template<typename T, typename U>
std::enable_if_t<std::is_same<typename T::traits_type, typename U::traits_type>::value,
                 std::shared_ptr<SumOperator<typename T::traits_type>>> operator+(
  const std::shared_ptr<T>& op1,
  const std::shared_ptr<U>& op2){
  return std::make_shared<SumOperator<typename T::traits_type>>(op1,op2);
}

请注意,由于SFINAE,如果没有operator+成员,此traits_type将无法正确匹配任何内容。

Full demo.