Вопрос

I need to implement a functor that takes any (!) function pointer when instantiated, analyses the argument types, stores the pointer and when operator() is called, does something with the pointer. The easiest case being, calling the function with its arguments.

I tried converting the function pointer to something like std::function and I get the error:

error: invalid use of incomplete type ‘struct std::function<void (*)(...)>’
/usr/include/c++/4.6/functional:1572:11: error: declaration of ‘struct std::function<void(*)(...)>’

I am using gcc 4.6.1, compiling with -std=c++0x

This is a minimal example:

#include <functional>

using namespace std;
typedef void (*F_vararg)(...);
class Foo
{
    public:
        template<typename... ARGS> Foo(function<F_vararg(ARGS... args)> f);
        ~Foo(){}
        template<typename... ARGS>void operator()(ARGS... args);
    private:
        F_vararg m_f;
};

template<typename... ARGS> 
Foo::Foo(function<F_vararg(ARGS... args)> f)
{
    m_f = f;
}

template<typename... ARGS>
void Foo::operator()(ARGS... args)
{
    m_f(args...);
}

void func1(double *a1, double *a2, double *b)
{    //do something 
}

int main(void)
{
    Foo func1_functor((std::function<void (*)(...)>)(func1));

    double a1[3] = {2.,3.,4.};
    double a2[3] = {2.2,3.2,4.2};
    double b[3] = {1.5,2.5,3.5};

    func1_functor(a1,a2,b);

    return 0;
}

This does NOT compile... If I don't declare the constructor as a template but with "F_vararg f" as the argument, and adjust the cast in the instantiation accordingly, it works (should it?) but I have no chance (?) of getting any information on the arguments of func1 in the constructor of the functor which I need.

Am I missing something? Is there another way to do that?

Thank you in advance !!!

cheers, Steffen

edit Wow, that was quick! I need that for postponing the execution of functions. The functor (or another class) should be able to decide whether and when to run a function. To decide that it will use the information gathered from the argument list.

I have looked at std::bind but I couldn't think of a way to achieve what I want...

Это было полезно?

Решение

Lose the typedef. A function that takes variable arguments is a specific type, it's not compatible with functions taking typed arguments, and it can't have parameter types specified later.

This should work instead:

template<typename... ARGS> Foo(function<void(*)(ARGS... args)> f);

Of course, what you really need is to template the class, so you can remember what arguments the function requires.

#include <functional>

template<typename... ARGS>
class Foo
{
    std::function<void(ARGS...)> m_f;
public:
    Foo( std::function<void(ARGS...)> f ) : m_f(f) {}
    void operator()(ARGS... args) const { m_f(args...); }
};

template<typename... ARGS>
Foo<ARGS...> MakeFoo(void(*f)(ARGS...)) { return Foo<ARGS...>(f); }

void func1(double *a1, double *a2, double *b)
{    //do something 
}

int main(void)
{
    auto func1_functor = MakeFoo(func1);

    double a1[3] = {2.,3.,4.};
    double a2[3] = {2.2,3.2,4.2};
    double b[3] = {1.5,2.5,3.5};

    func1_functor(a1,a2,b);

    return 0;
}

Demo: http://ideone.com/fnUg2

Другие советы

To be type-safe, Foo should also encode the type of the arguments. The question doesn't specify the use-case fully, so I'm not sure if it is required to be able to pass 'typeless' Foos around and still have each one somehow remember (at runtime) what the types of its arguments are. Anyway, this code will work with the example given in the qeustion.

#include<utility>

template<typename FunctionType>
struct Foo {
        FunctionType f;
        Foo(FunctionType f_) : f(f_) {}

        template<typename... Args>
        void operator() (Args&&... args) {
                f(  std::forward<Args>(args)... );
        }
};

template<typename FunctionType>
Foo<FunctionType> foo(FunctionType f) {
        return Foo<FunctionType>(f);
}

void func1(double *, double *, double *)
{    //do something 
}


int main() {
        auto x = foo(func1);
        double d[3] = {2,3,4};
        func1(d, d, d);
        x(d, d, d);
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top