Hea*_*eek 7 c++ templates metaprogramming
我正在尝试创建一组函数模板,可以使用不同类型和数量的参数,如下所示:
template <T0>
void call(T0 arg0);
template <T0, T1>
void call(T0 arg0, T1 arg1);
template <T0, T1, T2>
void call(T0 arg0, T1 arg1, T2 arg2);
template <T0, T1, T2, T3>
void call(T0 arg0, T1 arg1, T2 arg2, T3 arg3);
template <T0, T1, T2, T3, T4>
void call(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4);
[...]
Run Code Online (Sandbox Code Playgroud)
函数内的参数都被视为相同(作为单参数模板函数的参数).这是一个库,所以我可以接受额外的努力,如果这意味着更少的工作量或更愉快的库用户界面.
我不得不为不同的项目多次这样做,而且我非常厌倦必须手动手动编写所有这些项目.当我事先不知道使用该库的项目所需的最大参数数量时,情况会变得更糟.
在我开始编写Python脚本以生成所有重载之前,是否有一些元编程方法让编译器为我做这件事?
没有标准的方法可以做到这一点,但它可以在C++ 0x中完成,即使用称为"可变参数模板"的技术即将推出的(但尚未官方的)标准.在这里看一下您的真实例子.引用自己:
#include <iostream>
template<typename Format>
void meheer(const Format& format) {
std::cout << format << std::endl;;
}
template<typename Format, typename Elt, typename ... Args>
void meheer(const Format& format, const Elt & e, const Args&... args) {
std::cout << format << e;
meheer(format, args...);
}
template<typename Format, typename ... Args>
void ohai(const Format& format, const Args&... args) {
meheer(format, args...);
}
int main(int argc, char ** argv) {
ohai(1,2,3);
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
输出:(用GCC编译,带标志-std=c++0x)
12131
Run Code Online (Sandbox Code Playgroud)
从概念上讲,这类似于使用模式匹配的基本递归匹配(如在函数式语言中),但在编译时展开.
如果您不想包含一个尚未标准的功能,那么"使用python脚本的许多类似定义"方法并不是一个糟糕的方法.boost库使用类似的方法,但往往依赖于预处理器宏.如果您有兴趣,请查看Boost.Variant的来源,它会执行此操作.
您可以尝试执行与 Boost 相同的操作,例如在Boost.Function中(链接到模板标头)。他们使用Boost.Preprocessor来枚举给定数量的参数的各种内容。例如,考虑您想要重载 0-2 个参数的函数。传统的方式如下:
void foo(){...}
template<class T0>
void foo(T0 a0){...}
template<class T0, class T1>
void foo(T0 a0, T1 a1){...}
Run Code Online (Sandbox Code Playgroud)
现在 Boost 所做的就是将这些模板参数(class T0等)放入预处理器宏中,在函数内部使用它,然后针对不同数量的参数包含标头 3 次。例子:
// template header, no include guard
#define FOO_TEMPLATE_PARAMS BOOST_PP_ENUM_PARAMS(FOO_NUM_ARGS,class T)
#define FOO_PARAM(J,I,D) BOOST_PP_CAT(T,I) BOOST_PP_CAT(a,I)
#define FOO_PARAMS BOOST_PP_ENUM(FOO_NUM_ARGS,FOO_PARAM,BOOST_PP_EMTPY)
#if FOO_NUM_ARGS > 0
#define FOO_TEMPLATE template< FOO_TEMPLATE_PARAMS >
#else
#define FOO_TEMPLATE
#endif
FOO_TEMPLATE
void foo(FOO_PARAMS){...}
// cleanup what we've done
#undef FOO_TEMPLATE_PARAM
#undef FOO_TEMPLATE_PARAMS
#undef FOO_PARAM
#undef FOO_PARAMS
#undef FOO_TEMPLATE
Run Code Online (Sandbox Code Playgroud)
上面是模板头,我们称之为Foo_Template.h。现在我们只需将其包含在我们想要的参数数量中即可:
// Foo.h
#include <boost/preprocessor.hpp>
#define FOO_NUM_ARGS 0
#include "Foo_Template.h"
#define FOO_NUM_ARGS 1
#include "Foo_Template.h"
#define FOO_NUM_ARGS 2
#include "Foo_Template.h"
#define FOO_NUM_ARGS 3
#include "Foo_Template.h"
#define FOO_NUM_ARGS 4
#include "Foo_Template.h"
#undef FOO_NUM_ARGS
Run Code Online (Sandbox Code Playgroud)
完美的!通过更多的预处理器工作和样板“代码”,我们现在可以为任意数量的参数重载 foo!预处理器宏将扩展为如下所示:
// with FOO_NUM_ARGS == 0
#define FOO_TEMPLATE_PARAMS /*empty, because we enumerate from [0,FOO_NUM_ARGS)*/
#define FOO_PARAMS /*empty again*/
#define FOO_TEMPLATE /*empty, we got the 0 args version*/
void foo(){...}
// with FOO_NUM_ARGS == 1
#define FOO_TEMPLAtE_PARAMS class T0 /* BOOST_PP_ENUM is like a little for loop */
#define FOO_PARAMS T0 a0
#define FOO_TEMPLATE template< class T0 >
template< class T0 >
void foo( T0 a0 ){...}
// with FOO_NUM_ARGS == 3
#define FOO_TEMPLAtE_PARAMS class T0, class T1, class T2
#define FOO_PARAMS T0 a0, T1 a1, T2 a2
#define FOO_TEMPLATE template< class T0, class T1, class T2 >
template< class T0, class T1, class T2 >
void foo( T0 a0, T1 a1, T2 a2 ){...}
Run Code Online (Sandbox Code Playgroud)
但幸运的是,由于可变参数模板,我们在 C++0x 中不再需要这个了。我爱他们。
| 归档时间: |
|
| 查看次数: |
927 次 |
| 最近记录: |