1
votes

I want to write a function

template <class Arg>
tuple<int, double> calc(Arg arg);

It returns:

[arg,0] if arg is int,
[0,arg] if arg is double 
and [0,0] if arg is nor int or double. 

I implement this function comparing the type of arg (Arg), type of i (int) and type of d (double) and then equating i=arg or d=arg respectively. But if I want to use my function with a string or another type, which can not be converted to int/double, I have a conversion error (its clear, cause I can't equate char* to int, for example). How can I bypass this conversion const char* to int (or another inconvertible type to int)? Or maybe there is another implementation of this function?

#define GETTYPE(x) typeid(x).name()
template <class Arg>
    tuple<int,double> calc(Arg arg)
    {
        int i = 0;
        double d = 0;
        if (GETTYPE(arg) == GETTYPE(i))
        {
            i = arg;
        }
        else if (GETTYPE(arg) == GETTYPE(d))
        {
            d = arg;
        }
        return make_tuple(i, d);
    }
2
Don't use typeid::name. It's much better to use std::is_same in this situation - Fureeish
Please post the exact error message and show how you invoke the template. At a quick glance, template <class Arg> is usually specified as template <typename Arg>, as double and float aren't classes. - Ken Y-N
Thank you, I've fixed it - Yauhen Mardan
@KenY-N in this context, class and typename are treated the same in current standard, so your advice does not apply. class will happily be deduced to primitive types. - Fureeish

2 Answers

4
votes

If you do not need a C++17 code, you can use overloading

tuple<int, double> foo(int a) {
    return {a, 0.0};
}

tuple<int, double> foo(double a) {
    return {0, a};
}

template<typename T>
tuple<int, double> foo(T) {
    return {0, 0.0};
}

If you need a C++17 code :

template<typename T>
tuple<int, double> foo([[maybe_unused]] T a) {
    if constexpr (std::is_same_v<int, T>)
        return {a, 0.0};

    else if constexpr (std::is_same_v<double, T>)
        return {0, a};

    else
        return {0, 0.0};
}
1
votes

The simplest solution is to just have 3 separate overloads:

tuple<int, double> calc(int arg)
{
  return make_tuple(arg, 0.);
}

tuple<int, double> calc(double arg)
{
  return make_tuple(0, arg);
}

template < typename T >
tuple<int, double> calc(T arg)
{
  return make_tuple(0, 0.);
}

Alternatively you can use template specialisations:

template < typename T >
tuple<int, double> calc(T arg)
{
  return make_tuple(0, 0.);
}

template <>
tuple<int, double> calc< int >(int arg)
{
  return make_tuple(arg, 0.);
}

template <>
tuple<int, double> calc< double >(double arg)
{
  return make_tuple(0, arg);
}