为什么具有默认分配参数的函数不被接受为 0-arg 生成器?
Why is a function with default-assigned argument(s) not accepted as 0-arg Generator?
以下代码尝试使用 ns::generateInt()
作为 std::generate_n()
的 Generator
参数:
// 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
function/functor ,它有 0 个参数,但是 ns::generateInt()
的参数有一个默认值;如上所示,在非模板代码中,我可以不带参数调用 ns::generateInt()
。
如果对上述代码所做的唯一更改是...
int generateInt( /*int offset = 0*/ )
{
return /*offset +*/ rand() % 128;
}
...然后编译就好了:
$ g++ ./main.cpp
$
从编译器的角度来看这是怎么回事? 我的默认参数生成器函数是 invokable,有 0 个参数,所以 为什么它不能用作 std::generate_n()
的 Generator
参数?
仅仅因为 generateInt()
有一个默认参数值不会改变它有一个参数的事实,您可以在错误消息中看到:
_Generator = int (*)(int)
默认参数值不是函数类型的一部分。
当您直接调用 generateInt()
时,编译器知道 generateInt()
的完整声明,因此它知道它可以允许您省略默认的参数值。
但是,在 std::generate_n()
内部,编译器不知道 _Generator __gen
输入参数指向您的 generateInt()
函数。它所知道的是 __gen
指向 某个函数 其类型采用 int
参数,任何关于默认值的知识都丢失了。由于 std::generate_n()
未在对 __gen()
的调用中提供该参数值,您会收到编译器错误。
std::generate_n()
的 Generator
模板参数需要 一个不带参数的 Callable 类型。因此,only 可以按原样使用 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() );
来自 std::generate_n
的参考:
g - generator function object that will be called.
The signature of the function should be equivalent to the following:
Ret fun();
请注意,它说签名必须是Ret fun();
,不是,参数是可调用的 有 0 个参数。
您可以很容易地将调用包装在 lambda 中,以免更改 ns
:
中的代码
std::generate_n(std::back_inserter(v),
5,
[] { return ns::generateInt(); });
默认参数不会改变函数的签名。签名仍然包含具有默认值的参数类型。当一个函数接受一个参数,该参数是指向另一个不需要参数的函数的指针,但该参数被赋予一个指向确实接受参数(有或没有默认值)的函数的指针,那么你就有了类型不匹配。
以下代码尝试使用 ns::generateInt()
作为 std::generate_n()
的 Generator
参数:
// 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
function/functor ,它有 0 个参数,但是 ns::generateInt()
的参数有一个默认值;如上所示,在非模板代码中,我可以不带参数调用 ns::generateInt()
。
如果对上述代码所做的唯一更改是...
int generateInt( /*int offset = 0*/ )
{
return /*offset +*/ rand() % 128;
}
...然后编译就好了:
$ g++ ./main.cpp
$
从编译器的角度来看这是怎么回事? 我的默认参数生成器函数是 invokable,有 0 个参数,所以 为什么它不能用作 std::generate_n()
的 Generator
参数?
仅仅因为 generateInt()
有一个默认参数值不会改变它有一个参数的事实,您可以在错误消息中看到:
_Generator = int (*)(int)
默认参数值不是函数类型的一部分。
当您直接调用 generateInt()
时,编译器知道 generateInt()
的完整声明,因此它知道它可以允许您省略默认的参数值。
但是,在 std::generate_n()
内部,编译器不知道 _Generator __gen
输入参数指向您的 generateInt()
函数。它所知道的是 __gen
指向 某个函数 其类型采用 int
参数,任何关于默认值的知识都丢失了。由于 std::generate_n()
未在对 __gen()
的调用中提供该参数值,您会收到编译器错误。
std::generate_n()
的 Generator
模板参数需要 一个不带参数的 Callable 类型。因此,only 可以按原样使用 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() );
来自 std::generate_n
的参考:
g - generator function object that will be called. The signature of the function should be equivalent to the following:
Ret fun();
请注意,它说签名必须是Ret fun();
,不是,参数是可调用的 有 0 个参数。
您可以很容易地将调用包装在 lambda 中,以免更改 ns
:
std::generate_n(std::back_inserter(v),
5,
[] { return ns::generateInt(); });
默认参数不会改变函数的签名。签名仍然包含具有默认值的参数类型。当一个函数接受一个参数,该参数是指向另一个不需要参数的函数的指针,但该参数被赋予一个指向确实接受参数(有或没有默认值)的函数的指针,那么你就有了类型不匹配。