举例子最多的就是print, 因为你不知道使用者要print几个参数,但是当使用者一旦在使用这个函数时使用参数个数就是确定的,对于开发人员的的话,你总不能写0-N个参数的函数吧? 下面这种需要写N个参数,所以不现实。
template<typename T1>
print(T1 arg_1)
{
cout<<arg_1;
}
template<typename T1, typename T2, ....typename Tn>
print(T1 arg_1, T2 arg_2, .., Tn arg_n)
{
cout<<arg_1;
cout<<arg_2;
...
cout<<arg_n;
}
为此编译器提供了下面的方式, 在C++11的时候,如果使用可变参数的话一定是需要递归(很重要,不管函数模板还是类处理变长都需要),因为参数包args单个函数里面拆不开。
// 当可变参数包为0的时候走到这个分支
template<typename T1>
print(T1 arg_1)
{
cout<<arg_1<<endl;
};
template<typename T1, typename... Types>
print(T1 arg_1, Types... args)
{
cout<<arg_1<<endl;
print(args...);
}
这里需要补充一个模板推导的小知识:
#include
using namespace std;
template<int... Index>
struct IndexSquence
{
};
template<typename T, int... Index>
void test(T first, IndexSquence<Index...>)
{
};
int main()
{
test(1, IndexSquence<2,3,4>() );
return 0;
}
//下面是编译期的实例化结果,可以看到可以通过模板推导出来index的几个数值。
#ifdef INSIGHTS_USE_TEMPLATE
template<>
void test<int, 2, 3, 4>(int first, IndexSquence<2, 3, 4>)
{
}
#endif
拿这个数列干啥呢?比如对每个数字算平方,或者干啥都可以,这个知识要补充一下。
同上
下面的demo是根据上面的知识铺垫后的一个集成代码,标准是C++11, 需要好好研究研究,稍微解释一下实例化的顺序,当要生成一个IndexSequenceMaker的类的时候,需要要实例化一个子类,然后对N=0的情况给一个类的偏特化作为终止条件,设计的很巧妙,C++啥时候也学不完。
#include
#include
template <size_t... S>
struct IndexSequence {};
template <size_t N, size_t... S>
struct IndexSequenceMaker : public IndexSequenceMaker<N - 1, N - 1, S...> {};
template <size_t... S>
struct IndexSequenceMaker<0, S...> {
using Type = IndexSequence<S...>;
};
template <size_t N>
using MakeIndexSequence = typename IndexSequenceMaker<N>::Type;
template <typename T, typename F>
void ForEachTuple(T&& tuple, F&& consumer)
{
ForEachTupleInternal(std::forward<T>(tuple), std::forward<F>(consumer), MakeIndexSequence<std::tuple_size<T>::value> {});
}
template <typename T, typename F, size_t... S>
void ForEachTupleInternal(T&& tuple, F&& consumer, IndexSequence<S...>)
{
std::initializer_list<int> { (consumer(std::get<S>(tuple)), 0)... };
}
struct Consumer {
template <typename T>
void operator()(T&& value)
{
std::cout << value << std::endl;
}
};
int main(int argc, char* argv[])
{
ForEachTuple(std::make_tuple(1, 2.1, "Hello"), Consumer {});
return 0;
}
下面是c++14支持了序列生成
template <typename T, typename F>
void ForEachTuple(T&& tuple, F&& consumer)
{
// c++ 14 的 make_index_sequence
ForEachTupleInternal(std::forward<T>(tuple), std::forward<F>(consumer), std::make_index_sequence<std::tuple_size<T>::value> {});
}
template <typename T, typename F, size_t... S>
void ForEachTupleInternal(T&& tuple, F&& consumer, std::index_sequence<S...>)
{
std::initializer_list<int> { (consumer(std::get<S>(tuple)), 0)... };
}
int main(int argc, char* argv[])
{
// c++ 14 的 lambda 中 auto 作为参数
ForEachTuple(std::make_tuple(1, 2.1, "Hello"), [](const auto& value) -> void { std::cout << value << std::endl; });
return 0;
}