【问题标题】:Function default parameters are ignored忽略函数默认参数
【发布时间】:2017-09-13 19:37:44
【问题描述】:

对于这段简化的代码,我收到以下错误:

错误:参数太少而无法运行 std::cout

int g(int a = 2, int b = 1)
{
    return a + b;
}

template<class Func>
void generic(Func f)
{
    std::cout << f();
}

int main()
{
    generic(g);
}

我不知道为什么函数 f 的默认参数没有传递给函数 generic 的原因。它的行为就像 f 没有任何默认参数...

怎么了?

如何正确转发默认参数?

【问题讨论】:

  • 我猜在传递函数指针的时候,它已经为需要2个参数的函数选择了一个重载。
  • 语言律师提醒...ab 是函数参数。这些参数的默认 arguments 为 2 和 1,rsp。所以a是参数,a在运行时的值就是参数。

标签: c++ c++11 templates g++


【解决方案1】:

g 可能有默认参数,但是&amp;g 的类型仍然是int(*)(int, int),这不是可以不带参数调用的类型。在generic 中,我们无法区分——我们已经失去了关于默认参数的上下文。

您可以将 g 包装在 lambda 中以保留上下文:

generic([]{ return g(); });

【讨论】:

  • 是否有可能(没有bind)从g 获得int(*)(int)int(*)()
  • 也许我们很快就能做到这一点generic([]() =&gt; g());,对吧? :P(谢谢)
  • @tobi303 你不能用bind 来做 - 和这里一样的问题。必须是 lambda。
  • 嗯,这很有趣,它似乎是这样工作的。但是 lambda 是如何保存上下文的呢?
  • @ampawd 因为g() 是一个有效的表达式,所以您直接按名称调用它。是通过g 的名称查找为您获取默认参数,而不是通过g 的类型
【解决方案2】:

我认为此代码的错误消息很好地说明了为什么这是不可能的:

int g(int a=0,int b=0){return 0;}

typedef int (*F1)(int);

int main() {
    F1 x = g;
}

error: cannot initialize a variable of type 'F1' (aka 'int (*)(int)') with
an lvalue of type 'int (int, int)': different number of parameters (1 vs 2)
    F1 x = g;
       ^   ~

即使使用默认参数,g 的类型仍然是

int (*) (int,int)

这就是你实例化模板时得到的推论。

如果由于某种原因您不能使用 C++11 或更高版本(即没有 lambda,请参阅 Barry 的回答)并且您不介意一些样板文件,那么您可以使用函数对象:

#include <iostream>

struct g_functor {
    int operator()(int a=0,int b=0){ return a;}
};

template <typename T> void foo(T t) { t(); }

int main() { foo(g_functor()); }

请注意,您必须创建g_functor 的实例才能将其作为参数传递。

【讨论】:

  • 如果你要使用样板文件,你应该将g 改为一个函数对象——这样你仍然可以使用generic(g)
  • 是的,函数对象也很好的解决方案
  • @ampawd 函数对象只是可怜的 mans lambdas(或者 lambdas 只是具有一些更高级语法的函数对象)。我只是好奇地想知道如何在 C++98 中做到这一点。对我来说,这总是有助于更好地理解 C++11 的特性,因为它们中的大多数都是为了克服 C++98 的缺点而发明的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-20
  • 1970-01-01
  • 1970-01-01
  • 2011-08-30
  • 1970-01-01
  • 2020-04-11
相关资源
最近更新 更多