我们如何使用引用类型实例化模板函数?

时间:2018-01-09 04:33:36

标签: c++ c++11

C ++不会使用T = Hoge&来实例化模板。

一个最小的例子:

  • 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;
    }
    

我用以下内容编译了这些:g++ -std=c++11 main.cpp hoge.cpp。但它给出了链接器错误:

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)

接下来,我将f(h)中的main.cpp更改为f<Hoge &>,错误消失了。

为什么在第一种情况下没有调用f<Hoge &>(Hoge &)? 对于这种情况,我可以通过每次键入f<Hoge &>来避免错误。但是,当涉及到重载运算符时,它无法完成。

请告诉我如何解决此错误。

2 个答案:

答案 0 :(得分:16)

编译器将尝试推导出最简单的T模板。在这里,T=Hoge很好,因此编译器不会尝试更详细的表单。

你可以清楚地表明你的意图。请尝试以下方法:

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

T仍会被推断为Hoge,但您的函数f会获得参考。 这使读者可以直接在f原型中看到它。

当涉及到模板参数推导时,在编译器引擎下会发生很多规则。当我说编译器推断出最简单的T可能时,我真的偷工减料。这是一个有效的来源:cppreference

答案 1 :(得分:5)

您可以使用引用类型实例化函数。但是,编译器将 推导模板参数作为引用类型。您可以通过不让编译器推断出参数而是指定参数来验证您是否可以实例化函数模板OK:

f<Hoge&>(h);

如果您想获得推导的参考类型,则需要使用转发参考作为功能模板的参数:

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

当使用转发引用作为模板参数并传递Hoge参数时,根据参数的值类别推导出该参数:

Hoge       h;
Hoge const c;

f(h);       // T becomes Hoge&
f(c);       // T becomes Hoge const&
f(Hoge());  // T becomes Hoge