3

I have two overloads of operator(), one that takes a function reference that takes any type as its parameters and returns any type. And another one which takes a function reference that takes any type as its parameter but returns void. Upon instantiation of my class I get the following errors:

In instantiation of 'A<void, int>':
error: 'void A<T, F>::operator()(void (&)(F)) [with T = void, F = int]' cannot be overloaded
error: with 'void A<T, F>::operator()(T (&)(F)) [with T = void, F = int]'

template <typename T, typename F> struct A {
    void operator()(T (&)(F)) {}
    void operator()(void (&)(F)) {}
};

void f(int) {}

int main() {

    A<void, int> a;
    a(f);
}

These errors only occur when the first template argument T is void. I would like to know what I'm doing wrong and why I can't overload operator() this way?

template boy
  • 10,230
  • 8
  • 61
  • 97
  • 2
    You have defined two functions named `operator()` with identical signatures. What did you expect? – n. m. could be an AI Dec 23 '12 at 13:42
  • @n.m. If and only if `T` is `void` do I want to use the second `operator()` overload. That's basically what I was trying to do but Pubby cleared it up for me. – template boy Dec 23 '12 at 13:43
  • for the same reason why std::tuple has a broken constructor specification. see http://stackoverflow.com/questions/11386042/confused-by-default-constructor-description-of-stdtuple-in-the-iso-c-standar – Johannes Schaub - litb Dec 23 '12 at 13:55
  • The language/compiler doesn't know which definition you want to use, so it flags an error. There's no easy way to tell the compiler "if there are two, I want to use this one", so you have to provide only one definition. Pubby's suggestion is one way to make sure there's only one; another way is to use SFINAE and something like `std::enable_if`. If your `struct A` ever grows too large to specialize conveniently, you may want to research this second option. – n. m. could be an AI Dec 23 '12 at 14:06

1 Answers1

7

Well, if T is void then you have two function definitions with the exact same prototype - breaking ODR.

Try specializing your struct to prevent this:

template <typename T, typename F> struct A {
    void operator()(T (&)(F)) {}
    void operator()(void (&)(F)) {}
};

template <typename F> struct A<void, F> {
    void operator()(void (&)(F)) {}
};
Pubby
  • 51,882
  • 13
  • 139
  • 180