Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass pointer-to-template-function as function argument?

Say I want a C++ function to perform arithmetic on two inputs, treating them as a given type:

pseudo:

function(var X,var Y,function OP)
{
 if(something)
  return OP<int>(X,Y);
 else if(something else)
  return OP<double>(X,Y);
 else
  return OP<string>(X,Y);
}

functions that fit OP might be like:

template <class T> add(var X,var Y)
{
 return (T)X + (T)Y; //X, Y are of a type with overloaded operators
}

So, the question is what would the signature for function look like? If the operator functions are non-templated I can do it, but I get confused with this extra complexity.

like image 640
Mr. Boy Avatar asked Aug 15 '09 21:08

Mr. Boy


2 Answers

template <class OP> void function(OP op)
{
  // call with int
  op(1, 2);
  // or with double
  op(1.2, 2.3);
  // call with explicit template argument
  op.template operator()<int>(1, 2);
  op.template operator()<string>("one", "two");
}

struct Add
{
  template <class T> T operator ()(T a, T b)
  {
    return a + b;
  }
};

function(Add());
// or call with C++14 lambda
function([](auto a, auto b) { return a + b; });
like image 169
eyelash Avatar answered Oct 24 '22 20:10

eyelash


Template functions cannot be passed as template arguments. You have to manually deduce template arguments for this function before you pass it to another template function. For example, you have function

T sum(T a, T b)
{
    return a + b;
}

You want to pass it to callFunc:

template<typename F, typename T>
T callFunc(T a, T b, F f)
{
    return f(a, b);
}

You can't simply write

int a = callFunc(1, 2, sum);

You have to write

int a = callFunc(1, 2, sum<int>);

To be able to pass sum without writing int, you have to write a functor - struct or class with operator() that will call your template function. Then you can pass this functor as template argument. Here is an example.

template<class T>
T sum(T a, T b)
{
    return a + b;
}
template<class T>
struct Summator
{
    T operator()(T a, T b)
    {
        return sum<T>(a, b);
    }
};
template<template<typename> class TFunctor, class T>
T doSomething(T a, T b)
{
    return TFunctor<T>()(a, b);
    //Equivalent to this:
    //TFunctor<T> functor;
    //return functor(a, b);
}


int main()
{
    int n1 = 1;
    int n2 = 2;
    int n3 = doSomething<Summator>(n1, n2); //n3 == 3
    return 0;
}
like image 39
izogfif Avatar answered Oct 24 '22 19:10

izogfif