我认为函数模板参数只能通过类标识符声明,例如:
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);
该机制如何运作?你能举一个例子,其中基本类型可以用作函数模板参数吗?
答案 0 :(得分:2)
在我的旅行中,我发现模板参数有三个主要用途:基本类型:
一个是构建一个采用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<size_t>
作为访问元素的方法。以下是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";
}
我想您可以将此视为前两个示例的专业化。它是更多模板元编程技巧,在某些情况下证明是非常有用的。
答案 1 :(得分:1)
似乎您可能会对模板通常如下所示感到困惑:
template <class T> void Bar( T param );
此上下文中的类<{3}} 更具描述性:typename。这告诉您任何typename都可以用作模板参数,包括从模板生成的基本类型或类型。所以不要写上面的内容,你可以写:
template <typename T> void Bar( T param );
除了类型之外,您还可以将synonym类型实例传递给模板。这通常用于在类模板中设置数组大小,但还有许多其他用途。正如Praetorian在评论中提到的,您可以通过搜索some来找到更多信息。
答案 2 :(得分:1)
尽管语法允许 1 class
用于模板参数,例如:template <class T>
,但从来没有任何意图将它们限制为用户定义的类型。
换句话说,您可以始终传递基本类型作为模板参数,除非用户在模板内部的代码中做了一些事情来防止它,例如在模板中使用static_assert
或代码调用传递类型的成员函数。
对于非类型模板参数,您可以基本上指定任何类型。模板可以使用该类型的值进行实例化,也可以转换为该类型。
<子> 1。如果您愿意,可以使用typename
- 有些人更喜欢,因为它更好地传达了允许任何类型名称的想法。