4

I am trying to write some functionality where I need to save different functions and later extract their arguments' types. So I'm using the function signature as template parameter. But I get somewhat unexpected results. Here's the code:

#include <functional>
#include <iostream>

template <class T>
struct foo
{
    foo()
    {
        std::cout << "class T" << std::endl;
    }
};

template <class Ret, class Arg>
struct foo<Ret(Arg)>
{
    foo()
    {
        std::cout << "Ret(Arg)" << std::endl;
    }
};

template <class T>
void save(std::function<T>)
{
    new foo<T>();
}

int main(int argc, char* argv[])
{
    std::function<void(void)> someFoo;
    save(someFoo);
    return 0;
}

So if the variable someFoo is a function with type void(void), it instantiates the first template, foo<T>. But if I change it to void(int), than I get the desired specialized template instantiated. Why is that?

Barry
  • 267,863
  • 28
  • 545
  • 906
Pavel
  • 73
  • 5
  • `void(void)` is the same as `void()`. The second parameter of the specialization can't be matched so it falls back to the primary template. – David G Apr 29 '15 at 11:08
  • Might want to check: http://stackoverflow.com/questions/693788/c-void-arguments – Cássio Renan Apr 29 '15 at 11:08

2 Answers2

5

In C++, having a void argument is actually the same as having no argument at all (unlike in C, by the way). So it would match a specialization for Ret(), but it can't match a specialization for Ret(Arg).

Arkanosis
  • 2,119
  • 1
  • 13
  • 18
3

void(void) is the exact same as void() - the second void is optional and makes no difference.

That's why the first template with no parameters is used.

maja
  • 15,809
  • 16
  • 75
  • 116