我正在尝试创建一组可以采用不同类型和数量的参数的函数模板,如下所示:
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);
[...]
在函数内对参数进行相同的处理(作为单参数模板函数的参数)。这是一个库,所以我可以接受额外的努力,如果这意味着更少的工作量或更愉快的库用户界面。
对于不同的项目,我不得不多次这样做,而且我非常厌倦必须亲自手动编写所有这些项目。当我事先不知道使用该库的项目所需的最大参数数量时,情况会变得更糟。
在我开始编写Python脚本以生成所有重载之前,是否有一些元编程方法让编译器为我做这个呢?
答案 0 :(得分:6)
没有标准的方法可以做到这一点,但它可以在C ++ 0x中完成,即使用称为“可变参数模板”的技术即将推出的(但尚未官方的)标准。请参阅here以获取真实的示例。引用自己:
#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;
}
输出:(使用GCC编译,带有标记-std=c++0x
)
12131
从概念上讲,这类似于使用模式匹配的基本递归匹配(如在函数式语言中),但在编译时展开。
如果你不想包含一个尚未标准的功能,那么“使用python脚本的许多类似定义”方法并不是一个糟糕的方法。 boost库使用类似的方法,但往往依赖于预处理器宏。如果您有兴趣,请查看Boost.Variant的来源,这样做。
答案 1 :(得分:4)
你可以尝试和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){...}
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
以上是模板标题,我们称之为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
完美!通过更多的预处理器工作和样板“代码”,我们现在可以为任意数量的参数重载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 ){...}
但是由于可变参数模板,我们不再需要C ++ 0x,这是一种幸福。我爱他们。
答案 2 :(得分:3)
以下是我在代码中制作可变参数模板的方法,没有C ++ 0x支持和Boost(非常删节):
// blah.hpp
// (include guards)
#ifndef BLAH_MAX_PARAMETERS
// allow this to be changed to a higher number if needed,
// ten is a good default number
#define BLAH_MAX_PARAMETERS 10
#endif
#if BLAH_MAX_PARAMETERS < 0
// but don't be stupid with it
#error "Invalid BLAH_MAX_PARAMETERS value."
#endif
// include premade functions, to avoid the costly iteration
#include "detail/blah_premade.hpp"
// generate classes if needed
#if BLAH_MAX_PARAMETERS > BLAH_PREMADE_PARAMETERS
#define BOOST_PP_ITERATION_LIMITS (BOSST_PP_INC(BLAH_PREMADE_PARAMETERS), \
BLAH_MAX_PARAMETERS)
#define BOOST_PP_FILENAME_1 "detail/blah.hpp"
#include BOOST_PP_ITERATE()
#endif
这是“主要”包括。如您所见,它只是设置了所需的迭代次数,并确保存在足够的迭代次数。我包含一个预制文件,因为这个迭代(特别是多次使用时)可以真正增加你的编译时间。我预先制作了十个,所以默认情况下不进行迭代:
// detail/blah_premade.hpp
// (include guards)
// a bunch of manually made (however you want to do that)
// pastes of what our iteration normally generates
// allow this file to change the assumed count
#define BLAH_PREMADE_PARAMETERS 10
然后我们有了预处理器模板:
// detail/blah.hpp
// no header guards
#define N BOOST_PP_ITERATION()
// use N to generate code
#undef
就是这样。我留给你填写中间的任何你想要的东西;也许看看Xeo's answer。
答案 3 :(得分:1)
在C ++ 0x中有variadic templates。