使用可变参数数量调用模板函数指针

11
我希望编写一个函数,可以使用其它函数及其参数。以下是我的期望操作方式:
int sum(int a, int b) { return a + b }
int succ(int a)       { return a + 1 }
int size(char* str)   { return strlen(str) }

int call(???) { ??? }

int main() {
  cout << call(sum, 1, 2) << endl;
  cout << call(succ, 41) << endl;
  cout << call(size, "teste") << endl;
}

期望输出:

3
42
5

如何编写call函数(假设返回值始终相同)?我能想到的唯一方法是:

template<typename T> int call(T func, int a, int b) { return func(a, b) } 
template<typename T> int call(T func, int a)        { return func(a) } 
template<typename T> int call(T func, char* a)      { return func(a) } 

有没有办法用模板、va_list或其他方法解决这个重复的问题?

意图:

这是为了绘制几何图形图片,解析一个带参数方程式来绘制。例如:

Vector2i circle(float t, float radius) {
  return Vector2i(cos(t * 2*PI) * radius, sin(t * 2*PI) * radius);
}
// ...
draw(circle, 10);

draw函数内,将会多次调用circle函数并传入不同的t参数(介于0.01.0之间)。其他的参数将直接传递给函数,10将作为radius参数。(其中Vector2i是自定义类)


1
只是好奇,为什么不直接调用函数呢?这种晦涩的转移似乎没有任何意义。 - user195488
1
你能解释一下你实际要解决的问题,而不是一个看似可行的解决方案吗? - Mark B
如果您有一个支持可变模板的编译器,您可以这样做,但问题仍然存在...为什么要这样做呢?为什么不直接调用函数呢? - Praetorian
4
请使用boost :: bind(在0x中使用std :: bind),永远不要使用va_list,它是不安全、麻烦的垃圾代码。 - Cat Plus Plus
这是用于绘制几何图形、解析具有参数方程的函数以进行绘制。例如:Vector2i circle(float t, float r) {return Vector2i(cos(t*2*PI)*r, sin(t*2*PI)*r)}; 然后 draw(circle, 10),其中该函数将被多次调用,使用不同的 t 值(在 0.01.0 之间),而 10 则为 r 的值。(Vector2i 是自定义类) - Guilherme Bernal
@LBg 最好将这个澄清放到你的问题中,以避免任何混淆。 - Johannes Schaub - litb
3个回答

22

C++0x 可变参数模板:

template<typename Func, typename... Args>
auto call(Func func, Args&&... args)
-> typename std::result_of<Func(Args...)>::type
{
    return func(std::forward<Args>(args)...);
}

3
因为他没有要求使用C++0x解决方案,而是假定在SO上使用了C++解决方案,所以得到的答案是-1。 - user195488
5
“什么?C++0x就是C++,甚至在名称中都有体现。” - Cat Plus Plus
1
+1 是因为无论人们在标记 [tag:c++] 时是否默认包含 [tag:c++0x],这个答案都是有用的。@0A0D,你看过 [tag:c++] 的标签维基页面吗?它确实提到了 C++0x。 - R. Martinho Fernandes
3
好的,我会尽力完成您的翻译工作。以下是翻译的结果:@0A0D: 这个蠢蠢的downvote真是无聊。我们明确将0x方案标记为0x以避免混淆,但这并不意味着它突然就不是C ++了。此外,一年后标签wiki将变成0x,那又怎样呢? - Cat Plus Plus
7
@0A0D:评论一个踩票是好的。一定要陈述你的意见。但是人们不同意也没关系。 - Yochai Timmer
显示剩余10条评论

3

添加另一个模板变量:

template<typename T, typename U> 
int call(T func, U a) { return func(a) } 

template<typename T, typename U, typename V> 
int call(T func, U a, V b) { return func(a,b) }

是的,但我也想让它能够使用任意数量的参数,并调用 func - Guilherme Bernal
@LBg:这不是你所问的。 - user195488
1
你唯一能做的就是使用stdarg传递参数列表,但你只能将它们作为列表传递,而不能进行正确的调用。除非你根据参数数量进行切换。http://en.wikipedia.org/wiki/Stdarg.h - Yochai Timmer

2

为当前C++解决方案提供一个简单的#define,这样怎么样:

#define call(FUNC, ...) FUNC(__VA_ARGS__)

这里是演示。建议您使用更好的名称,而不是像call这样的通用名称,因为您正在使用#define

可变参数宏是在C++0x中引入的(但由于它们是有效的C99,因此是常见的扩展)。 - Luc Danton
@Luc,我认为大多数编译器都支持它。但无论如何,我不知道这个事实。 - iammilind

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接