c++ - 为什么具有默认分配参数的函数不被接受为 0-arg 生成器?

标签 c++ stl generator default-arguments

以下代码尝试使用 ns::generateInt() 作为 Generatorstd::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() 的参数?

最佳答案

仅仅因为 generateInt() 有一个默认参数值并不会改变它有一个参数的事实,您可以在错误消息中看到这一点:

_Generator = int (*)(int)

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

当您直接调用generateInt()时,编译器知道generateInt()的完整声明,因此它知道它可以允许您可以省略默认参数值。

但是,在 std::generate_n() 内部,编译器不知道 _Generator __gen 输入参数指向您的 generateInt() 函数。它所知道的是__gen指向某个函数,其类型采用int参数,任何默认值的知识都会丢失。由于 std::generate_n() 在调用 __gen() 时未提供该参数值,因此您会收到编译器错误。

std::generate_n()Generator 模板参数需要 Callable不带参数的类型。因此,可以按原样将 1 参数 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() );

关于c++ - 为什么具有默认分配参数的函数不被接受为 0-arg 生成器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61828657/

相关文章:

python - 将生成器包装到缓冲区中?

asynchronous - 如何在 Tornado 中将异步函数和生成函数包装在一起?

c++ - 从 void 指针增加值

c++ - Boost 属性树 (XML) 删除空行

c++ - 带有 vector 作为键的 STL 映射

c++ - std::map<UnicodeString, UnicodeString> 的 ofstream 输出产生地址而不是字符串

c++ - 该项目不会将整数作为二进制读取并将它们作为二进制输出到新文件

c++ - 使用 Qt 信号和槽 (C++) 在两个 child 之间传输数据

c++ - 'windows.h',其他平台呢?

python - 这个函数可以用生成器理解来表达吗?