为什么有默认参数的函数不被接受为0-arg Generator?

问题描述 投票:2回答:1

下面的代码试图使用 ns::generateInt() 作为 Generator 争论 std::generate_n():

// main.cpp

#include <vector>
#include <algorithm>
#include <ctime>

static int _tmp = ( srand( time( NULL ) ), 0 );

namespace ns
{

  int generateInt( int offset = 0 )
  {
    return offset + rand() % 128;
  }

}

int main( int argc, char* argv[] )
{
  std::vector<int> v;
  int tmp = ns::generateInt(); // Fine to call ns::generateInt() w/ 0 args

  std::generate_n( std::back_inserter( v ),
                   5,
                   ns::generateInt ); // Not accepted as 0-arg Generator
  return 0;
}

这段代码产生了以下编译错误。

$ g++ --version && g++ ./main.cpp
g++ (GCC) 9.2.1 20190827 (Red Hat 9.2.1-1)
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

In file included from /usr/include/c++/9/algorithm:62,
                 from ./main.cpp:4:
/usr/include/c++/9/bits/stl_algo.h: In instantiation of ‘_OIter std::generate_n(_OIter, _Size, _Generator) [with _OIter = std::back_insert_iterator<std::vector<int> >; _Size = int; _Generator = int (*)(int)]’:
./main.cpp:26:36:   required from here
/usr/include/c++/9/bits/stl_algo.h:4493:18: error: too few arguments to function
 4493 |  *__first = __gen();
      |             ~~~~~^~

我知道 std::generate_n() 签字 Generator 的函数函数,接受0个参数,但参数为 ns::generateInt() 有一个默认值;如上所示,在非模板化的代码中,我可以调用 ns::generateInt() 没有参数。

如果对上面的代码只做了这样的修改... ...

  int generateInt( /*int offset = 0*/ )
  {
    return /*offset +*/ rand() % 128;
  }

...那么它的编译就会很好。

$ g++ ./main.cpp
$

从编译器的角度看,这是怎么回事? 我的默认参数生成器函数是 可调用 有0个参数,所以 为什么它不能作为 Generator 争论 std::generate_n()?

c++ stl generator default-arguments
1个回答
2
投票

只是因为 generateInt() 有一个默认的参数值并不能改变它有一个参数的事实,你可以在错误信息中看到。

_Generator = int (*)(int)

默认参数值不是函数类型的一部分。

当你调用 generateInt() 径直的完整声明,编译器知道 generateInt() 所以它知道它可以允许你省略默认的参数值。

但是,在 std::generate_n(),编译器不知道 _Generator __gen 输入参数指向您的 generateInt() 功能。 它只知道 __gen 指的是 某种功能 其类型为 int 争论。任何关于默认值的知识都会丢失. 而且由于 std::generate_n() 的调用中没有提供该参数值。__gen(),你会得到编译器错误。

Generator 的模板参数 std::generate_n() 需要 a 可调用 类型,不接受任何参数。 所以,这个 只是 你可以使用你的1-argument generateInt() 按原样 std::generate_n() 是把它包在一个0参数的lambda或漏斗内,例如

std::generate_n( std::back_inserter( v ),
                   5,
                   []{ return ns::generateInt(/*0*/); } );
struct genInt
{
    int operator()(){ return ns::generateInt(/*0*/); }
};

std::generate_n( std::back_inserter( v ),
                   5,
                   genInt() );

2
投票

从引用中可以看到 std::generate_n:

g - 将被调用的生成函数对象。 函数的签名应等同于以下内容。

Ret fun()。

注意,它说的是 签名 必须 Ret fun();, 争论是 可调用 的0个参数。

你可以很容易地用一个lambda来包装这个调用,这样就不会改变在 ns:

std::generate_n(std::back_inserter(v),
                5,
                [] { return ns::generateInt(); }); 

1
投票

缺省参数不会改变函数的签名。签名仍然包含有缺省值的参数类型。当一个函数接受的参数是指向另一个不需要参数的函数的指针,但这个参数被赋予了指向一个需要参数的函数的指针(有或没有缺省值),那么你就有一个类型不匹配。

© www.soinside.com 2019 - 2024. All rights reserved.