0

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.

irowe
  • 638
  • 11
  • 21
  • @JeJo Very helpful! Care to explain why that is necessary? If you added this as an answer I'd accept+upvote. – irowe Feb 27 '23 at 23:05
  • Because forwarding ref will prevent the plane array to pointer decay. If it happens like that, there is no specialization available there to handle. I guess jejo's suggestion is for this reason. Alternatively `const&` might also prevent this. – LernerCpp Feb 27 '23 at 23:11

0 Answers0