Question

C++

I'm trying to implement a function wrapper via a (function object) class (variadic) template. The class has as its only data member a function pointer that is initialized by or assigned the function pointer it is wrapping. The parametrized constructor takes a function pointer and initializes the member by it. The operator() method takes argument(s) (or none) and calls the wrapped function with them. At least that's the idea. I get many errors, which I mark with comments. VC11 (with the November 2012 CTP, to enable variadic templates) gives me error C2091: function returns function in all but one of the marked areas. The last error is different, and I comment its full description in the code. g++ gives mostly the same errors, albeit with different code numbers.

#include <iostream>

template <typename R, typename... Tn>
class func
{
    R (*fptr)(Tn...); // C2091
public:
    func() : fptr(nullptr) {}
    func( R (*f) (Tn...) ) : fptr(f) {} // C2091
    R operator()(Tn... args)
    { // C2091
        return fptr(args...);
    }
    func& operator=( R (*f) (Tn...) ) // C2091
    {
        fptr = f;
        return *this;
    }
};

int foo(int a, int b)
{
    std::cout << "foo\n";
    return 0;
}

int main()
{
    func<int(int, int)> myfunc;
    myfunc = foo; // C2679: binary '=' : no operator found which takes
    // a right-hand operand of type 'int (__cdecl *)(int,int)' (or 
    // there is no acceptable conversion)
}

Why am I getting these errors? For example, I don't see how the parametrized constructor returns anything, or how the declaration of the data member returns anything. Isn't the data member declaration in the form of a function pointer declaration? For example, doesn't int (*g)(int); declare a pointer that points to a function that takes an int and returns an int?

Edit/Addendum:

I see from the answers that int(int, int) is only one type and that I need partial specialization to get the effect I want. But, what produces the error in my code? If I comment out myfunc = foo, I still get the other errors. func<int(int, int)> myfunc; calls the default constructor. typename R gets instantiated to int(int, int), and typename... Tn becomes empty. The data member R (*fptr)(Tn...); becomes R (*fptr)();, and fptr is therefore a function pointer that points to a function that takes zero arguments and returns an R. If R is int(int, int), then is R a function pointer type or a function type? If it's the latter, then I can understand the context of the error message.

Was it helpful?

Solution

int(int, int) is one single type. If you want to pass it like that and unwrap it, you need partial specialization:

template <typename> struct func;         // leave undefined

template <typename R, typename ...Args>
struct func<R(Args...)>                  // specialized for typename = R(Args...)
{
    // ...
};

OTHER TIPS

Your class is parameterized by the return value and types of arguments, spelled out separately. But when instantiating, you try to parameterize it by a function type, a la std::function. Make it func<int, int, int> myfunc;. With this change, your code works.

You need partial specialization.

Here's a working example:

template <typename T>
class func;

template <typename R, typename... Tn>
class func<R(Tn...)> {
    typedef R (*fptr_t)(Tn...);
    fptr_t fptr;
public:
    func() : fptr(nullptr) {}
    func(fptr_t f) : fptr(f) {}
    R operator()(Tn... args) {
        return fptr(args...);
    }
    func& operator=(fptr_t f) {
        fptr = f;
        return *this;
    }
};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top