【问题标题】:In which cases one needs to specify the template's argument `types` specifically?在哪些情况下需要特别指定模板的参数“types”?
【发布时间】:2011-08-29 16:24:04
【问题描述】:
// Function declaration.
template <typename T1, 
          typename T2, 
          typename RT> RT max (T1 a, T2 b);

// Function call.
max <int,double,double> (4,4.2)

// Function call.
max <int> (4,4.2)

一种情况可能是您需要指定返回类型。

还有其他需要手动指定参数类型的情况吗?

【问题讨论】:

    标签: c++ templates


    【解决方案1】:

    (1)当函数没有参数并且它仍然是template类型时,那么您可能必须明确指定参数

    template<typename T>
    void foo ()
    {}
    

    用法:

    foo<int>();
    foo<A>();
    

    (2)你想区分价值和参考

    template<typename T>
    void foo(T obj)
    {}
    

    用法:

    int i = 2;
    foo(i); // pass by value
    foo<int&>(i); // pass by reference
    

    (3)需要另一种类型来推导而不是自然类型。

    template<typename T>
    void foo(T& obj)
    {}
    

    用法:

    foo<double>(d);  // otherwise it would have been foo<int>
    foo<Base&>(o); // otherwise it would have been foo<Derived&>
    

    (4) 为单个模板参数提供了两种不同的参数类型

    template<typename T>
    void foo(T obj1, T obj2)
    {}
    

    用法:

    foo<double>(d,i);  // Deduction finds both double and int for T
    

    【讨论】:

    • 最后一个强制di 加倍,因此T 加倍。
    【解决方案2】:

    如果函数模板参数出现在函数参数列表中,则不需要指定模板参数。例如,

    template<typename T>
    void f(const T &t) {}
    

    这里T是一个模板参数,它出现在函数参数列表中,即const T &amp;t。所以调用这个函数时不需要指定模板参数:

    f(10); //ok
    

    由于10类型int,所以编译器可以从中推导出模板参数T,T变成int

    请注意,由于类型推导是通过使用函数参数的信息完成的,因此称为template argument deduction现在继续阅读。

    如果模板参数没有出现在函数参数列表中,那么您必须提供模板参数。示例:

    template<typename T>
    void g(const int &i) {}
    

    注意g()f() 不同。现在T 不会出现在函数参数列表中。所以:

    g(10); //error
    g<double>(10); //ok
    

    请注意,如果函数模板也模板化了返回类型,并且返回类型与函数参数列表中出现的类型不同,那么您必须提供返回类型:

    template<typename T>
    T h(const T &t) {}
    

    由于返回类型T与函数参数相同,所以可以从函数参数中进行类型推导:

    h(10); //ok - too obvious now
    

    但如果你有这个:

    template<typename R, typename T>
    R m(const T &t) {}
    

    那么,

    m(10);  //error - only T can be deduced, not R
    m<int>(10);  //ok
    

    请注意,尽管函数模板 m 已模板化为两种类型:RT,但我们在调用它时只提供了一种类型。也就是说,我们写了m&lt;int&gt;(10),而不是m&lt;int,int&gt;(10)。写后者没有坏处,但如果你不这样做,也可以。但有时您必须同时指定两者,即使可以推断出一种类型 T。就是类型参数的顺序不同如下图:

    template<typename T, typename R> //note the order : its swapped now!
    R n(const T &t) {}
    

    现在,您必须提供两种类型:

    n(10); //error - R cannot be deduced!
    n<int>(10); //error - R still cannot be deduced, since its the second argument!
    n<int,int>(10); //ok
    

    这里的新东西是:类型参数的顺序也很重要

    无论如何,这仅涵盖基本概念。现在我建议您阅读一些关于模板的好书,以了解有关类型推导的所有高级知识。

    【讨论】:

    • @VishalSharma:这取决于您当前的专业水平。您可以从The Definitive C++ Book Guide and List 中选择一两个。如果您分享一些您编写的代码以便让我评估您的专业知识,那么我可能会帮助您选择一本您想阅读的好书。
    【解决方案3】:

    一般来说,当编译器无法自行判断时,您需要显式指定类型。正如您所提到的,这通常发生在返回类型被模板化时,因为无法从函数调用中推断出返回类型。

    模板类也有同样的问题——实例化 std::vector 使编译器无法确定向量存储的类型,因此您需要指定 std::vector&lt;int&gt; 等等。

    类型解析仅在函数参数的情况下执行,因此将其视为特殊情况可能更容易;通常,编译器无法猜测要使用什么类型。

    【讨论】:

      【解决方案4】:

      简单的答案是,当编译器无法自行推断类型时,或者当您希望使用与编译器会推断。

      编译器无法推断出类型有不同的情况。因为类型推导仅适用于参数(如重载决议的情况),如果返回类型不作为可推导的参数出现,那么您必须指定它。但是还有其他情况下类型推导不起作用:

      template <typename R> R f(); // Return type is never deduced by itself
      template <typename T>
      T min( T const & lhs, T const & rhs );
      min( 1, 2 );                 // Return type is deducible from arguments
      min( 1.0, 2 );               // T is not deducible (no perfect match)
      min<double>( 1.0, 2 );       // Now it is ok: forced to be double
      min<double>( 1, 2 );         // Compiler will deduce int, but we want double
      
      template <typename T>
      void print_ptr( T* p );
      print_ptr<void>( 0 );        // 0 is a valid T* for any T, select manually one
      
      template <typename T>
      T min( T lhs, T rhs );
      int a = 5, b = 7;
      min<int&>(a,b)++;            // Type deduction will drop & by default and call
                                   // min<int>(a,b), force the type to be a reference
      
      template <typename C>
      typename C::value_type
      min_value( typename C::const_iterator begin, typename C::const_iterator end );
      std::vector<int> v;
      min_value<std::vector<int> >( v.begin(), v.end() ); 
                                       // Argument type is not deducible, there are 
                                       // potentially infinite C that match the constraints
                                       // and the compiler would be forced to instantiate
                                       // all
      

      可能有更多原因导致无法推断出参数类型,您可以查看标准中的 §14.8.2.1 了解从函数调用中推断出参数的细节。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-08
        • 1970-01-01
        • 2021-07-05
        • 2011-05-15
        • 1970-01-01
        相关资源
        最近更新 更多