I have a set of template classes inherited from a single base class:

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

The following code for a specific set of properties works without problems:

 class TraitsExample{ public: typedef double scalar_t; }; int main(){ typedef typename TraitsExample::scalar_t scalar_t; auto op1=std::make_shared<Pover_of_Number<TraitsExample>>(2.); auto op2=std::make_shared<Mult_by_Number<TraitsExample>>(10.); auto sumop=std::make_shared<SumOperator<TraitsExample>>(op1,op2); scalar_t value=2.; std::cout<<sumop->apply(value)<<std::endl; } 

Having such a set of classes I need to overload the + operator. For example:

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

However, when compiling such a code, a problem occurs with automatic pattern recognition and an error occurs: template argument deduction/substitution failed .

Can someone suggest a code that allows the addition operator to be properly overloaded in this case?

PS: for convenience, you can find the code link

Closed due to the fact that off-topic participants Abyx , aleksandr barakin , user194374, αλεχολυτ , Grundy 13 Aug '16 at 19:06 .

It seems that this question does not correspond to the subject of the site. Those who voted to close it indicated the following reason:

  • “Questions asking for help with debugging (“ why does this code not work? ”) Should include the desired behavior, a specific problem or error, and a minimum code for playing it right in the question . Questions without an explicit description of the problem are useless for other visitors. See How to create minimal, self-sufficient and reproducible example . " - Abyx, aleksandr barakin, Community Spirit, αλεχολυτ, Grundy
If the question can be reformulated according to the rules set out in the certificate , edit it .

  • Make a minimal example that reproduces the problem. - Abyx
  • In my opinion this is the minimum example. There are three class heirs using the TypeTraits pattern. It is necessary to overload the addition operator from these three classes 3 = 1 + 2. The difficulty lies precisely in the presence of all these components together, so simplification simply removes this problem as such. - QuantumNik
  • Uh, you want an addition operator for (smart) pointers ? - VladD
  • What's wrong with that? I can arbitrarily overload any operators. I'm not trying to add these pointers, I explicitly set the type returned by the overloaded operator - a new pointer to a well-known object that knows exactly what needs to be done when calling a member function. - QuantumNik
  • Alexolut has a minimal example, and you have some kind of wall of code. - Abyx

1 answer 1

To begin with, your code (or rather the problematic part of it) can be simplified to the following:

 #include <iostream> #include <memory> template <class T> struct B {}; template <class T> struct D : B<T> {}; template <class T> void operator+ (const std::shared_ptr<B<T>>&, const std::shared_ptr<B<T>>&) {} int main() { std::shared_ptr<D<int>> sd(new D<int>); std::shared_ptr<B<int>> sb = sd; sd + sb; } 

In this embodiment, it is not compiled . The reason is that the types of arguments in template functions do not allow implicit conversion. Those. for example, instead of std::shared_ptr<B<T>> you cannot use std::shared_ptr<D<T>> , since they are not connected by the relation "basic - derivative", but only have corresponding transformative constructors.

If the first argument is corrected to const std::shared_ptr<D<T>>& , then the code is already compiled .

Or you can make the operator non-template:

 //template <class T> void operator+ (const std::shared_ptr<B<int>>&, const std::shared_ptr<B<int>>&) {} 

in this case, the compilation will also be successful .

Which of these solutions will suit you better - decide for yourself:

  1. Make inheritance between real argument types.
  2. To correct the signature for a more special case.
  3. Make the function non-template.