I have a function template that I'd like to be able to instantiate for a reference to an array (C-style). However, when I try to call it, the deduced type never matches.
Here's a minimal example:
#include <iostream>
class FooClass{
public:
template<typename T>
void Bar(T);
};
template<>
void FooClass::Bar(int (&p)[3]){
std::cout << p[0] << p[1] << p[2] << std::endl;
}
int main(){
auto myFoo = FooClass();
int foo[3] = {};
myFoo.Bar<int(&)[3]>(foo); // #0, Works
myFoo.Bar(foo); // #1
myFoo.Bar(&foo); // #2
int (&ref_foo)[3] = foo;
myFoo.Bar(ref_foo); // #3
myFoo.Bar(&ref_foo); // #4
}
All of the above calls that don't explicitly name template parameters at the call site result in linker errors.
#1 and #3 result in
(.text+0x88): undefined reference to
void FooClass::Bar<int*>(int*)
#2 and #4 result in
undefined reference to
void FooClass::Bar<int (*) [3]>(int (*) [3])
Why is writing the template parameter explicitly (ie, myFoo.Bar<int(&)[3]>(foo)
) necessary?
If I run objdump -t [obj-file] |c++filt | grep Bar
on the compiled object, I can see where the signature for the instantiated function doesn't match either of the calls:
000000000000010a l F .text 0000000000000015 _GLOBAL__sub_I__ZN8FooClass3BatIJRA3_iEEEvDpT_
0000000000000000 g F .text 000000000000005a void FooClass::Bat<int (&) [3]>(int (&) [3])
0000000000000000 *UND* 0000000000000000 void FooClass::Bat<int*>(int*)
0000000000000000 *UND* 0000000000000000 void FooClass::Bat<int (*) [3]>(int (*) [3])
I understand that this can be side-stepped by using containers instead of C-style arrays, but I'd like to know if this is possible to fixed as posed.
Many of the related questions already on StackOverflow mention that you cannot partially specialize a member function. However, in this case, I am explicitly (fully) specializing the Bar
member function, and the FooClass
is not templated.