0

The following code does not compile with G++ (although I believe it should):

#include <iostream>

template <unsigned N>
struct foo_traits {
    typedef const char ArrayArg[N];
    typedef int Function (ArrayArg *);
};

template <unsigned N>
int foo (typename foo_traits<N>::Function *ptr) {
    return ptr(&"good");
}

int bar (const char (*x)[5]) {
    std::cout << *x << "\n";
    return 0;
}

int main ()
{
    return foo(bar);
}

I checked this with GCC 4.4 through 4.7, and I get a template argument deduction failure. With 4.7.1:

prog.cpp: In function ‘int main()’:
prog.cpp:21:19: error: no matching function for call to ‘foo(int (&)(const char (*)[5]))’
prog.cpp:21:19: note: candidate is:
prog.cpp:10:5: note: template<unsigned int N> int foo(typename foo_traits<N>::Function*)
prog.cpp:10:5: note:   template argument deduction/substitution failed:
prog.cpp:21:19: note:   couldn't deduce template parameter ‘N’

If I use an explicit template argument (i.e., foo<5>(bar)), it compiles fine. If I use a version of the code without the typedefs, it compiles fine:

#include <iostream>

template <unsigned N>
int fixfoo (int (*ptr) (const char (*)[N])) {
    return ptr(&"good");
}

int bar (const char (*x)[5]) {
    std::cout << *x << "\n";
    return 0;
}

int main ()
{
    return fixfoo(bar);
}

Is the failing code supposed to compile (i.e., did I make a silly mistake)?

jxh
  • 69,070
  • 8
  • 110
  • 193

1 Answers1

2
int foo(typename foo_traits<N>::Function *ptr);

The signature makes it a non-deductible context, so you must include the template arguments so that the value N is known and so consequentially the type of the pointer ptr be known as well.

Your second example compiles because the type of the signature through bar can be deduced.

David G
  • 94,763
  • 41
  • 167
  • 253
  • What causes something to be in a "non-deductible context". Is that language from the standard? – jxh Jun 10 '13 at 21:22
  • @jxh I'm not sure if it's terminology from the Standard, but think about it: `typename foo_traits::Function* ptr` requires the signature to know the value of `N` *before* the argument is past. What if `foo_traits` has different specializations based on the value of `N`, and therefore has different types for `Function` based on those values? – David G Jun 10 '13 at 21:25
  • `foo` and `foo_traits`, are not instantiated until the call where the type of the argument to `foo` is known. Are you saying the compiler is not able to deduce the template argument for `foo_traits` even knowing the type of the supplied function argument to `foo`? – jxh Jun 10 '13 at 21:36
  • @jxh Yup, that's correct. And its most likely for the reasons I said in my last comment. – David G Jun 10 '13 at 21:38
  • Scratch that last question, I'll write a new question. – jxh Jun 10 '13 at 21:43