3

Possible Duplicate:
Workaround for non-deduced context

GCC cannot deduce parameters for this 'simple' function. Is there any way to help the compiler a bit?

template<int a> struct A
{
    template<int b> struct B
    {
    };
};

template<int a, int b> void test(typename A<a>::template B<b> param) { }

int main()
{
    A<1>::B<2> b;

    test<1,2>(b); // works
    test(b);      // doesn't work
}

error message from GCC 4.7.1:

test.cpp: In function 'int main()':
test.cpp:15:8: error: no matching function for call to 'test(A<1>::B<2>&)'
test.cpp:15:8: note: candidate is:
test.cpp:8:29: note: template<int a, int b> void test(typename A<a>::B<b>)
test.cpp:8:29: note:   template argument deduction/substitution failed:
test.cpp:15:8: note:   couldn't deduce template parameter 'a'
Community
  • 1
  • 1
Watu
  • 63
  • 1
  • 7
  • @BoPersson: I agree it is closely related, but because this question involves nested templates, the answer provided there doesn't work. – Vaughn Cato Sep 28 '12 at 14:13
  • @BoPersson: My mistake. Having the function be a friend template function does work. That may be a better solution in some cases. – Vaughn Cato Sep 28 '12 at 14:28

1 Answers1

5

Although it seems like a simple deduction, what you are wanting the compiler to do would actually be quite complicated and slow to do in general, and it isn't supported by C++.

One way around this is to create another non-nested class that has all the template parameters in one place. You can then make this appear to be a nested class by deriving from it:

template<int a,int b> struct A_B {
  /* define your class here */
};

template<int a> struct A
{
    template<int b> struct B : A_B<a,b> {/*nothing here*/};
};

template<int a, int b> void test(A_B<a,b> param) { }

int main()
{
    A<1>::B<2> b;

    test<1,2>(b); // works
    test(b);      // works too
}

C++11 also supports template aliasing, which makes this a little cleaner, although it isn't widely supported yet:

template<int a> struct A
{
    template<int b> using B = A_B<a,b>;
};

This question is closely related:

Workaround for non-deduced context

The answers provided there are useful for your situation as well. If you can make your function be a friend, then you can do this:

template<int a> struct A
{
    template <int b>
    struct B
    {
    };

    template <int b>
    friend void test(B<b> param)
    {
    }
};
Community
  • 1
  • 1
Vaughn Cato
  • 63,448
  • 5
  • 82
  • 132
  • In general `param` will suffer from slicing or will request casting (if passed by reference or pointer) – Rost Sep 28 '12 at 13:39
  • @Rost: Agreed it will slice. I've added a comment to make it clearer that nothing should be in the derived nested class. I don't see why a cast would be necessary for pointers and references though. – Vaughn Cato Sep 28 '12 at 14:02
  • It doesn't make much sense to define `B` as nested into `A` in this case - it still will be duplicated in global scope and could not use any types/members defined in `A`... – Rost Sep 28 '12 at 14:20
  • @Rost: I think that may often be true, but sometimes you want a nested a type just to make the names simpler. – Vaughn Cato Sep 28 '12 at 14:25