1

I'm trying to learn about boost mpl and I was wondering if something like this would be possible. Specifically, is it possible to conditionally typedef a function based on a template parameter? Something along the lines of this toy example:

template<typename arg1, typename arg2, typename rtype>
rtype getValue()
{
    typedef boost::conditional<
    // typedef boost::mpl::if_<
        boost::is_same<rtype, double>,
        double multiply(double a, double b),
        int multiply(int a, int b) 
    > function;
    function test;
    return test(arg1::value, arg2::value);
}

I tried the above code and got the error that "template argument 2 is invalid". So I was wondering if there is a way to turn the function definition into a valid type since it is a valid typedef?

I am also aware there are many other ways to do this. I don't want a work around since this is an attempt to learn.

joshu
  • 463
  • 8
  • 18

2 Answers2

2

A typedef applies to types a function is not a type.

A function may have a type, for example, double multiply(double, double) has the type double (*)(double, double). However, the type is not actually linked to the function: double add(double, double) has the same type as double multiply(double, double).

What you may be able to do is create a functor, which is a class (a type) that can act like a function.

For example, something like:

class DoubleMultiplier
{
public:
    double operator()(double value1, double value2) const
    {
        return value1 * value2;
    }
};

class IntMultiplier
{
public:
    int operator()(int value1, int value2) const
    {
        return value1 * value2;
    }
};

template<typename arg1, typename arg2, typename rtype>
rtype getValue()
{
    typedef boost::conditional<
    // typedef boost::mpl::if_<
        boost::is_same<rtype, double>,
        DoubleMultiplier,
        IntMultiplier 
    > function;
    function test;
    return test(arg1::value, arg2::value);
}

I'm assuming your specific example is a simplified version of something more complex. DoubleMultiplier and IntMultiplier do the same thing so you could make a templated Multiplier instead -- of course you could also just multiply arg1::value1 by arg2::value2 directly in getValue().

Community
  • 1
  • 1
Steven
  • 754
  • 3
  • 6
1

Functions are no types. You can write a typedef with a function but that's just creating a type alias not the function type. For actual functions you could create a template using a function pointer as template argument and turn the function into a type this way. For example

template <typename T, T(*fun)(T, T)>
struct arithmetic_fun {
    T operator(T x, T y) const { return fun(x, y); }
};

template <typename T>
T multiply(T x, T y) {
    return x * y;
 };

using int_multiply = arithmetic_fun<int, &multiply<int>>;
// ...

Using this approach is kind of unnecessary, though, as the standard C++ library contains class templates for the common arithmetic operations anyway. Of course, you could just use these making all this meta-programming moot to start with:

   template <typename A1, typenam A2, typename R>
   R getValue() {
       using function = std::multiplies<R>;
       function test;
       return test(A1::value, A2::value);
    }
joshu
  • 463
  • 8
  • 18
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380