Avoid specifying redundant template parameters containing a templated function pointer

Let's assume we have this code:

template <class T, void (*u)(T&)>
void Foo()
{
   // store the function u internally . . .
}

      

There are reasons to do something like this, and I will not try to enter them. However, is there a way to avoid specifying the type T

when called Foo()

? For example, compilation usually requires:

Foo<int, MyIntFunction>();

      

But if this int

one can be inferred from a function pointer, is it possible:

Foo<MyIntFunction>();

      

EDIT . I know the solution is to pass the actual function pointer as a function parameter, however this is not desirable here as it has some drawbacks in an intensive loop.

+3


source to share


3 answers


In this example, u is not a function pointer, it is a type (function pointer signature). If you want to store a function pointer, you need to pass it.

template<class T, class F = void(*)(T&)>
void Foo(F f)
{
  // store the function pointer f here
}

      

called like this:



struct SomeType {};
void bar(SomeType& x);

Foo(&bar);

      

Is this what you want to do?

+3


source


Short answer: I don't think it is possible.

Long ... When you call a template function, you cannot omit the first parameter and specify the second: the compiler will try to match yours MyIntFunction

against the template parameter T

. Typically, you can specify the first, but omit the second if the compiler can infer the second template parameter. This is not an option in this case, because you want to explicitly specify the second parameter.

The second template parameter has a dependency ( T

) on the first template parameter. Hence, reordering the template parameters is also not an option.



The best way would be to define it as Richard suggested:

template<class T>
void Foo(T f)
{
   int a(1);
   f(a); // this forces f to be a function taking an int as parameter
}

      

+1


source


Here is a dirty implementation that basically does what the OP asked for. It depends on too many assumptions, but there can be at least something to discuss. The idea is to pre-specify all possible types that can serve as an argument to the function, and then infer that type.

#include<iostream>

template<typename T>
struct TD; //type display

template<typename FunctionType, typename T, typename ... Ts>
struct ArgumentDeduction
{
    typedef typename std::conditional<std::is_same<void, typename std::result_of<FunctionType(T)>::type>::value
                                     , T
                                     , typename ArgumentDeduction<FunctionType, Ts ...>::type
                                     >::type type;
};

template<typename FunctionType, typename T>
struct ArgumentDeduction<FunctionType, T>
{
    typedef typename std::conditional<std::is_same<void, typename std::result_of<FunctionType(T)>::type>::value
                                     , T
                                     , void
                                     >::type type;    
};


template<typename FunctionType
       , typename T = typename ArgumentDeduction<FunctionType, int, double>::type >
void foo()
{
    TD<T>();
}

struct AvoidConversion
{
    struct DummyType{};
    template<typename T> DummyType operator()(T x) { return DummyType(); }    
};

struct Bar : public AvoidConversion
{
    using AvoidConversion::operator();

    void operator()(int x);
    //void operator()(double x);   //try also this
};

int main()
{
    foo<Bar>();  //calls the foo<Bar,int> version    
}

      

One of the basic assumptions is the form of the functor Bar

, which in principle accepts any type, but has a corresponding type implementation void

for only one permitted type.

Again, I don't think this is quite useful, but I think this is the closest thing to the OP's question so far.

DEMO


EDIT: Otherwise, i.e. Without AvoidConversion

in the above code, the compiler will perform the implicit conversion, and the argument output gives true

for all types that convert to each other (such as int

is output when there is only a function that accepts a double , for example ).

If anyone sees a way to avoid this ugly hack AvoidConversion

and infer the type of the parameter somehow more gracefully, I'd be interested to see it.

+1


source







All Articles