Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can we instantiate template functions with a reference type?

Tags:

c++

c++11

C++ does not instantiate templates with, say T = Hoge&.

A minimal example:

  • hoge.h:

    #include<cstdio>
    class Hoge
    {
      public:
        Hoge()
          : hoge(0)
        {
        }
        ~Hoge()
        {
        }
    
        int hoge;
        void print() { printf("%d\n", hoge); }
    };
    
    template<typename T>
    void f(T a);
    
  • hoge.cpp:

    #include "hoge.h"
    template<typename T>
    void f(T a)
    {
      a.print();
    }
    
    template void f<Hoge &>(Hoge &a);
    
  • main.cpp:

    #include "hoge.h"
    int main(void)
    {
      Hoge h;
      f(h);
      return 0;
    }
    

I compiled these with: g++ -std=c++11 main.cpp hoge.cpp. But it gives a linker error:

Undefined symbols for architecture x86_64:
  "void f<Hoge>(Hoge)", referenced from:
      _main in aa-e35088.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Next, I changed f(h) in main.cpp to f<Hoge &>, and the error disappeared.

Why is f<Hoge &>(Hoge &) not called in the first case? For this case, I can avoid errors by typing f<Hoge &> every time. But, when it comes to overloaded operators, it cannot be done.

Please tell me how to solve this error.

like image 418
naughie Avatar asked Jan 09 '18 04:01

naughie


2 Answers

The compiler will try to deduce the simplest template T possible. Here, T=Hoge is fine, so the compiler doesn't try more elaborated forms.

You can clearly state your intent though. Try the following:

template<typename T>
void f(T& a);

T will still be deduced as Hoge, but your function f will get a reference. This allows the reader to clearly see that directly in f prototype.

When it comes to template argument deduction, there is a lot of rules occurring under the compiler hood. When I state the compiler deduce the simplest T possible, I'm really cutting corners. Here is a fiable source: cppreference

like image 117
johan d Avatar answered Oct 22 '22 09:10

johan d


You can instantiate the function with a reference type just the way you did. However, the compiler will not deduce the template argument as a reference type. You can verify that you can instantiate the function template OK by not having the compiler deduce the argument but rather specifying the argument:

f<Hoge&>(h);

If you want to get a reference type deduced you'll need to use a forwarding reference as an argument of your function template:

template <typename T>
void f(T&& a);

When using a forwarding reference as a template argument and passing an Hoge argument, the argument is deduced according to the value category of argument:

Hoge       h;
Hoge const c;

f(h);       // T becomes Hoge&
f(c);       // T becomes Hoge const&
f(Hoge());  // T becomes Hoge
like image 39
Dietmar Kühl Avatar answered Oct 22 '22 10:10

Dietmar Kühl