【问题标题】:fundamental types as a function templates parameters基本类型作为函数模板参数
【发布时间】:2013-10-03 15:39:06
【问题描述】:

我以为函数模板参数只能通过类标识符来声明,例如:

template<class T1, class T2> void fun(T1 a, T2 b){}

但我发现了其他可以将基本类型用作参数的示例:

template<int R, int C> 
void fun(double (&arr)[R][C])
{
     for(int i = 0; i < R; ++i)
     {
          for(int j = 0; j < C; ++j)
          {
               cout<<arr[i][j]<<" ";
          }
          cout<<endl;
     }
}

函数执行如下所示:

fun(myArray);

该机制如何运作?你能再给我一个基本类型可以用作函数模板参数的例子吗?

【问题讨论】:

标签: c++


【解决方案1】:

在我的旅行中,我发现模板参数作为基本类型的三个主要用途:

其中一个是构建一个采用 C 样式数组的函数模板。这就是您在此处发布的内容,但更常见的是,我看到这适用于 char 数组,如下所示:

template <size_t N, typename Char>
string MakeString (Char const (&chars)[N])
{
    return string (chars, N); 
}

int main()
{
    string hi = MakeString ("Hello");
    cout << hi; 
}

另一个用途是使用模板元编程构建一种廉价的属性系统。例如,假设您有一堆用于表示某些有线协议中的消息的类,并且出于测试目的,您希望将消息类的实际大小与规范规定的大小进行比较。

enum MsgType
{
    MsgType_Foo,
    MsgType_Bar
};

class FooMsg
{
    uint32_t mField;
    char mName [9];
};

class BarMsg
{
    char mPrice [8];
    static const size_t SpecSize = 8;
};

template <MsgType MT> size_t SpecSize();

template <> size_t SpecSize <MsgType_Foo> ()
{
    return 13;
}

template <> size_t SpecSize <MsgType_Bar> ()
{
    return 9;
}

int main()
{
    assert (SpecSize <MsgType_Foo> () == sizeof (FooMsg));
    assert (SpecSize <MsgType_Bar> () == sizeof (BarMsg));
}

请注意,如果您运行此程序,除非您执行特定于平台的操作(例如 #pragma pack (push, 1))来修复打包,否则断言将失败。这是测试旨在捕获的内容之一!

最后,另一个常见的用法更具体,但该技术可以应用于您自己的代码。在 Boost.Tuple 和现在的 C++11 中,tuple 类使用模板函数 get&lt;size_t&gt; 作为访问元素的方法。这是取自en.cppreference.com的示例:

#include <iostream>
#include <string>
#include <tuple>

int main()
{
    auto t = std::make_tuple(1, "Foo", 3.14);
    // index-based access
    std::cout << "(" << std::get<0>(t) << ", " << std::get<1>(t)
              << ", " << std::get<2>(t) << ")\n";
}

我猜你可以把这看作是前面两个例子的特化。这是更多模板元编程技巧,在某些情况下非常有用。

【讨论】:

    【解决方案2】:

    尽管它们的语法允许1class 用于模板参数,例如:template &lt;class T&gt;,但从来没有任何意图将它们限制为用户定义的类型。

    换句话说,您可以始终将基本类型作为模板参数传递除非用户在模板内的代码中做了一些事情来阻止它,例如使用static_assert 或模板内的代码调用传递类型的成员函数。

    对于非类型模板参数,您基本上可以指定任何类型。模板可以使用该类型的值进行实例化,也可以转换为该类型。


    1。如果您愿意,可以使用typename - 有些人喜欢,因为它更好地传达了允许任何类型的名称的想法。

    【讨论】:

      【解决方案3】:

      您似乎对模板通常如下所示感到困惑:

      template <class T> void Bar( T param );
      

      在这种情况下类有一个synonym,它更具描述性:typename。这告诉您任何类型名都可以用作模板参数,包括原始类型或从模板生成的类型。因此,您可以写而不是写上面的内容:

      template <typename T> void Bar( T param );
      

      除了类型之外,您还可以将 some 类型的实例传递给您演示的模板。这通常用于在类模板中设置数组大小,但还有许多其他用途。正如Praetorian在cmets中提到的,您可以通过搜索non-type template arguments找到更多信息。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-07-06
        • 1970-01-01
        • 2021-03-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-25
        相关资源
        最近更新 更多