下面的代码试图使用 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()
?
只是因为 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() );
从引用中可以看到 std::generate_n
:
g - 将被调用的生成函数对象。 函数的签名应等同于以下内容。
Ret fun()。
注意,它说的是 签名 必须 Ret fun();
, 不 争论是 可调用 的0个参数。
你可以很容易地用一个lambda来包装这个调用,这样就不会改变在 ns
:
std::generate_n(std::back_inserter(v),
5,
[] { return ns::generateInt(); });
缺省参数不会改变函数的签名。签名仍然包含有缺省值的参数类型。当一个函数接受的参数是指向另一个不需要参数的函数的指针,但这个参数被赋予了指向一个需要参数的函数的指针(有或没有缺省值),那么你就有一个类型不匹配。