【问题标题】:C++ - rules around function template instantiationC++ - 围绕函数模板实例化的规则
【发布时间】:2011-12-09 16:19:45
【问题描述】:

我现在正在学习函数模板,我想研究一下函数模板实例化的一些规则。所以我写了以下代码:

#include <iostream>

template <typename>
int check(int x) {
  return x * 2;
}

int main() {
  std::cout << check<double>(10) << std::endl; // #1
  std::cout << check<>(10) << std::endl;         // #2
  std::cout << check(10) << std::endl;            // #3
  return 0;
}

#1、#2 和#3 行并没有一起编译,每次尝试我只留下其中一个并注释其余部分。 因此,当 #1 启用时,我没有编译错误,并且打印了正确的答案“20”。据我了解, "check" 调用模板实例化机制,因此真正创建了 "int check(int)" 函数(模板参数的类型不没有任何影响)。 启用#3 时,出现编译错误"error: no matching function for call to 'check(int)'",这是合理的,因为我正在尝试调用" check(int)" 函数不存在。我的问题是关于 #2 案例:在这种情况下,我得到了相同的 “错误:没有匹配函数调用'check(int)'”。不应该调用 "check(10)" 触发模板实例化机制吗?

【问题讨论】:

  • "不应该调用"check(10)" 触发模板实例化机制吗?" 你的问题的答案是:用什么参数?

标签: c++ templates function instantiation overloading


【解决方案1】:

您没有在 中放置任何模板参数。编译器如何知道要实例化哪个模板函数?请注意,您的模板函数是:

template <typename>
int check(int x) 

如果你把它改成这样:

template <typename T>
int check(T x) 

然后检查(10)应该没问题,因为编译器可以从参数中知道类型。

【讨论】:

    【解决方案2】:

    我不得不说,通常模板不会这样:(

    试试这个:

    template<typename T>
    T check(T x){
        return x*2;
    }
    

    【讨论】:

      【解决方案3】:

      您将获得的唯一模板实例化是使用

      check<double>(10)
      

      其他人不实例化模板。此外,对于函数模板的全部功能,包括模板参数作为

      template<typename T>
      T check(T x) {
        return x*2;
      }
      

      然后使用模板参数推导的力量你可以调用

      check(10.0);   // instantiates check<dobule>
      check(3);      // instantiates check<int>
      

      a = MyObject();
      check(a);         // instantiates check<MyObject>
      

      【讨论】:

        【解决方案4】:

        #2 如果可以推断出模板参数,则将是有效的。

        #include <iostream>
        
        template <class T>
        void foo(T t)
        {
            std::cout << "Template " << t << '\n';
        }
        
        void foo(int n)
        {
            std::cout << "Not template " << n << '\n';
        }
        
        int main()
        {
            foo(10); //calls non-template function 
                     //because matching non-template preferred over function templates
        
            foo<>(10); //calls the template function, empty brackets indicate you want
                       //the template overload, type is deduced from passed argument.
        
        }
        

        另一种可能性,如果函数模板有默认参数(仅在 C++11 中合法)。

        template <class T = void>
        int foo()
        {
            return 10;
        }
        
        int main()
        {
            return foo<>(); //same as foo<void>();
        }
        

        【讨论】:

          【解决方案5】:

          如果不传递模板参数,则相当于查找没有模板参数的函数(即不实例化模板)。在这种情况下,添加的&lt;&gt; 没有任何意义,因为没有重载。

          由于您拥有的函数实际上并未将模板用于任何事情,因此编译器无法推断类型 T,但如果您这样编写:

          template <typename T>
          T check(T x) {
              return x * 2;
          }
          

          那么所有 3 种情况都会起作用,因为它推断出类型 T。更多解释见https://stackoverflow.com/a/797632/888641

          注意:您可以使用typenameclass,它们在此处执行完全相同的操作。

          【讨论】:

          • 谢谢!我添加“”的原因是在 Vandevoorde 的“C++ Templates: The Complete Guilde”一书中写道,像“check”这样的调用会强制使用函数的模板版本(在函数模板的上下文中提到过重载)
          • 这并不意味着什么。如果你有一个重载,那么它会更喜欢模板而不是其他匹配的重载。
          • 那么如果没有超载,就意味着什么?
          • @user1090010 如果存在模板版本非模板或专用版本,则添加&lt;&gt; 告诉编译器使用模板版本。
          猜你喜欢
          • 2010-09-18
          • 1970-01-01
          • 2011-10-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多