Zebrafish
Zebrafish

Reputation: 14108

Why don't these functions decay to a function pointer?

I had a class which held a function pointer to be called, and now I've come across a situation where I would like that callable function to hold a self-contained reference/value (lambda). So I create my templated class to accept either function pointers or lambdas like this:

template <typename FunctionType>
class MyClass
{
public:
    MyClass(FunctionType function) : function(function) {}
    FunctionType function;
};

However it seems that each each time that this class is instantiated the compiler creates a different 'type' of class, as shown below:

int main()
{
    MyClass foo([]() {return 5; });
    MyClass foo2([]() {return 5; });
    MyClass foo3([]() {return 5; }); // ALL THREE OF THESE SEEM TO BE DIFFERENT TYPES
    MyClass foo4(static_cast<int(*)()> ([]() {return 5; })); // I THINK I CAN FORCE THEM TO BE THE SAME TYPES BY CASTING
    MyClass foo5(static_cast<int(*)()> ([]() {return 5; }));
    MyClass foo6(static_cast<int(*)()> ([]() {return 5; }));

    std::cout << typeid(foo).name() << '\n';
    std::cout << typeid(foo2).name() << '\n';
    std::cout << typeid(foo3).name() << '\n';
    std::cout << typeid(foo4).name() << '\n';
    std::cout << typeid(foo5).name() << '\n';
    std::cout << typeid(foo6).name() << '\n';
}

The output from this is:

class MyClass<class <lambda_e39b14fd1b959adc3c33a259b5258211> >
class MyClass<class <lambda_de164f9f0bca248459ade49332a364c3> >
class MyClass<class <lambda_9fcf071b66983e924cb117ca1e77c4c6> >
class MyClass<int (__cdecl*)(void)>
class MyClass<int (__cdecl*)(void)>
class MyClass<int (__cdecl*)(void)>

As I'll be creating hundreds or thousands of these I'd like for this not to be the case if at all possible. Most functions I'll pass to my class should be of the same type except for the occasional different lambda that I'll be needing. So is it the case the compiler is creating a different type every time I pass the same function type? It doesn't seem very efficient if that's the case. If it must be the case what's the best way to reduce the number of class types the compiler creates? I think I achieved it by casting to function pointer at the creation of the class, but this seems like a terrible way of doing it.

Upvotes: 1

Views: 320

Answers (1)

cigien
cigien

Reputation: 60268

You could make your class store a function pointer instead, like this:

template <typename Ret, typename ...Args>
class MyClass
{
public:
    MyClass(Ret (*function)(Args...)) : function(function) {}
    Ret (*function)(Args...);
};

Then you can store the lambda, by explicitly decaying it to a function pointer:

MyClass foo( + []() {return 5; });

and then only one class will be instantiated per function signature (whether it's a lambda or a function).

Here's a demo.

Upvotes: 5

Related Questions