为什么未命名的参数有用?

时间:2016-04-04 21:02:31

标签: c++ function parameter-passing most-vexing-parse

我很困惑为什么你可以定义像

这样的函数
int func_useless(int) { return 2; }

将未命名的int作为输入,但不执行任何操作,与

不同
int func_useful(int a) { return a; }

例如,您可以致电

int x = func_useless(3); // x is 2

需要将int传递给func_useless,但不会产生任何结果。

何时传递不能使用的东西会有用?为什么这是该语言的一个特征?

5 个答案:

答案 0 :(得分:2)

  • 回调接口;另一个库可能需要具有特定签名的回调,但您的回调并不关心特定参数的值。
  • 当你只关心参数的类型而不关心它的值时。

    • 可能是因为该类型的所有值都是等效的,例如std::nullptr_t或标记类型,例如std::allocator_arg_tstd::nothrow_tstd::piecewise_construct_tstd::input_iterator_tag。< / LI>
    • 可能是因为该参数仅用于控制重载决策,例如:

      template<class T> 
      auto do_foo(const T& t, int) -> decltype(t.foo()) { return t.foo(); }
      template<class T>
      void do_foo(const T& t, long) { /* default implementation */ }
      
      // call t.foo() if valid, otherwise provide a default implementation
      template<class T>
      decltype(auto) foo(const T& t) { return do_foo(t, 0); }
      

      do_foo的第二个参数的值无关紧要;它只用于控制do_foo(t, 0)调用时的do_foo调用的重载分辨率,通过使第一个更好。

      同样,我们有operator++()(前缀)和operator++(int)(后缀)及其--对应物; postfix ++ / --运算符的实现很少关注int参数的值;它存在消除前缀和后缀的歧义。

答案 1 :(得分:2)

一个用途是标签调度,这是模板编程中一种有用的技术:

#include <iostream>

struct ping_type {};
struct pong_type {};

static constexpr ping = ping_type {};
static constexpr pong = pong_type {};

void action(ping_type) {
  std::cout << "ping" << std::endl;
}

void action(pong_type) {
  std::cout << "pong" << std::endl;
}

int main()
{
    action(ping);    
    action(pong);
}

答案 2 :(得分:1)

这是一个用例。你有一个函数,它接受一个函数,并用它做一些事情:

int sumFrom0To9(int *func(int)) {
    int acc = 0;
    for (int i = 0; i < 10; i++) { acc += func(i); }
    return acc;
}

你可以传入你想要的任何单个arg函数,包括比如这样的东西:

int identity(int) { return 1; }

答案 3 :(得分:0)

我无法想出任何有用的理由。

我期待你得到的是最令人烦恼的解析:

int main()
{
    int funk1();
    int funk2(int());

    funk2(funk1);
}

这是一个声明,你不需要这里的名字。它们可能在定义点命名。

编辑:

其实我确实想到了一个用途:

int whatnot() { return 6; }

void somefun(int (*callback)(int()))
{
    callback(whatnot);
}

int my_callback(int()) { return 42; }

int main()
{
    somefun(my_callback);
}

my_callback不需要或不使用函数参数,但需要接受它才能遵守somefun指定的回调接口。

答案 4 :(得分:0)

如果要保留函数的二进制接口(不更改其签名)但不再对参数有任何用处并希望关闭有关未使用参数的编译器警告,则未命名的参数有时会很有用。