The following code compiles fine (just a minimal example, the actual code has more of a reason for this particular layout):
template<int A>
class Foo {
template<int B>
friend int bar(Foo<A> a, Foo<B> b) {
return A * B;
}
};
int main() {
return bar(Foo<0>(), Foo<1>());
}
However, I would like to separate the declaration from the definition and put the function definition outside the class definition. I've tried doing it as you would for a member function:
template<int A> template<int B>
int bar(Foo<A> a, Foo<B> b) {
return A * B;
}
But that fails to compile because it doesn't seem to be valid syntax:
error: too many template-parameter-lists
However, merging the two template parameter lists in this definition (template<int A, int B>
) gives a linker error:
undefined reference to `int bar<1>(Foo<0>, Foo<1>)'
That leads me to believe that different template parameter lists cause the compiler/linker to interpret the definition of bar
as a different function than the declaration.
So my question is: how can I define a friend function outside of the class definition when the class and function have separate template parameters?
I think that there is no way to do this. Well there is but not generically. You can always explicitly write the overloads for each A
:
template<int B>
int bar(Foo<0> a, Foo<B> b) {
return 0 + B;
}
Basically, the reason is that a different bar
overload is defined for each instantiation of Foo
. For example, for Foo<0>
you'll get a
template<int B>
int bar(Foo<0>, Foo<B>);
For each instantiation of Foo
, you will get a new bar
template. All those bar
s are independent, because they use a template parameter that exists outside of bar
itself (from the outer template that is).
You can't use the double template<>
syntax because that would mean you have two things (class, function, ...) that are a template. This is not the case here, as you only have bar
as a template. There is nothing else for the first/second template<>
.
You can't merge them, because as you saw, you'll get a different function. If you look at the instantiated bar
above for Foo<0>
, you can see that this is different than:
template<int A, int B>
int bar(Foo<A>, Foo<B>);
The instantiated version will always be a better match because it doesn't have to deduce anything for the first parameter.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With