Timocafé
Timocafé

Reputation: 765

operator + and float argument

I have a curious issue with template, I am trying to make a basic addition between a template class and "float/double/int" type. It is very basic but if I do:

template<class T>
class toto{
    T a;
};

template<class T>
toto<T> operator+(toto<T> const&, T&){
     std::cout <<  "hello " <<std::endl;
}

int main(){
     toto<float> t;
     toto<float> d = t +2.3;
}

It will not compile because 2.3 is considered like a double, it does not match the signature. I could use a second template parameter for my operator+ as

template<class T, class D>
toto<T> operator+(toto<T> const&, D&){
     std::cout <<  "hello " <<std::endl;
}

It compiles, execute correctly but too dangerous D can be everything. An alternative is to create different signature with float, double or int (O_O). Boost::enable_if seems my solution but in the doc I read:

template <class T>
T foo(T t,typename enable_if<boost::is_arithmetic<T> >::type* dummy = 0);

Apply this method to the operator* doest not work, because the compiler complains default arguments are forbidden.

Any suggestions ?

Cheers,

++t

Upvotes: 4

Views: 150

Answers (3)

Columbo
Columbo

Reputation: 60999

Use a non-deduced context for the second parameter. And a const-reference as the parameter, to allow rvalues.

template <typename T> struct identity {using type = T;};
template <typename T>
using identity_t = typename identity<T>::type;

template<class T>
toto<T> operator+(toto<T> const&, identity_t<T> const&)
{
     std::cout <<  "hello " <<std::endl;
}

A non-deduced context will cause deduction to ignore the call argument for a certain parameter as the invoked template parameters cannot be deduced. In some scenarios, as here, that is desired since inconsistent deductions are not possible anymore. In other words, the type of the second parameter fully depends on the first argument of the call, not the second (which may be implicitly converted).

toto<float> d = t + 2.3;

Should now compile, Demo.

Upvotes: 5

&#214;&#246; Tiib
&#214;&#246; Tiib

Reputation: 11014

The enable_ifs tend not be too beautiful to read but other means feel worse. I typically use return value type for enabling a function because it is located most up front:

#include<type_traits>
#include<iostream>

template<class T>
class toto
{
    T a;
};

template<typename T,typename D> 
typename std::enable_if< std::is_arithmetic<D>::value
                       // && some other constraint
                       // && etc.
    , toto<T> >::type operator+(toto<T> const&, D const&)
{
    std::cout <<  "hello " <<std::endl;
}

int main() 
{
    toto<float> t;
    toto<float> d = t +2.3;
}

Upvotes: 1

Anton Savin
Anton Savin

Reputation: 41321

You can use enable_if like this:

template<class T, class D, typename = typename std::enable_if<std::is_arithmetic<D>::value>::type>
toto<T> operator+(toto<T> const&, const D&){
    std::cout <<  "hello " <<std::endl;
    return toto<T>();        
}

Demo

Upvotes: 1

Related Questions