阅读代码时,我们会找到一些这样的函数。
g_spawn_async(NULL, new_argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL);
我认为没有人能弄清楚每个参数的含义是什么。为了理解代码,我们必须找到函数的声明。
gboolean g_spawn_async (const gchar *working_directory,
gchar **argv,
gchar **envp,
GSpawnFlags flags,
GSpawnChildSetupFunc child_setup,
gpointer user_data,
GPid *child_pid,
GError **error);
如何在C ++中调用类似以下格式的函数?
g_spawn_async(working_directory=NULL,
argv=new_argv,
envp=NULL,
flags=G_SPAWN_SEARCH_PATH,
child_setup=NULL,
user_data=NULL,
child_pid=NULL,
error=NULL);
我认为这个会更具可读性,我可以在不查找函数声明的情况下理解代码。
我知道Python可以做到这一点。 C ++如何做到这一点?
答案 0 :(得分:8)
C ++本身不支持此功能,因此您无法使用任何旧的现有功能。如果您正在创建自己的API,则可以使用所谓的Named Parameter Idiom来模拟它。链接中的示例:
File f = OpenFile("foo.txt")
.readonly()
.createIfNotExist()
.appendWhenWriting()
.blockSize(1024)
.unbuffered()
.exclusiveAccess();
答案 1 :(得分:5)
这在C或C ++中是不可能的。
我理解你的痛苦。我个人认为,如果一个函数有超过9000个参数,这是一个糟糕的设计标志,特别是如果它们中的大多数是NULL
或占位符值。例如,许多POSIX标准化函数采用某种struct
,将所有必要的值积累成一个易于理解的参数。
答案 2 :(得分:4)
不,这不可能。但您可以将NULL
值分配给变量,然后将它们作为参数传递,如果它有助于您的可读性!
g_spawn_async(working_directory, argv, envp,flags,child_setup , user_data, child_pid, error);
答案 3 :(得分:2)
BOOST参数库可以帮助您。它运作良好,便携.... 见http://www.boost.org/doc/libs/1_54_0/libs/parameter/doc/html/index.html
答案 4 :(得分:1)
这当然是可能的。它甚至不是特别困难, 但它确实涉及很多代码。像下面这样的东西 可以用:
enum MyFuncParamId
{
myA,
myB,
myC,
myD,
unknown
};
class MyFuncParam
{
union OneParam
{
double aOrB;
C c;
int d;
OneParam() {}
~OneParam() {}
};
OneParam myParam;
MyFuncParamId myId;
public:
MyFuncParam( MyFuncParamId id, double value )
: myId( id )
{
switch ( myId ) {
case myA:
case myB:
myParam.aOrB = value;
break;
case myC:
assert( 0 );
abort();
case myD:
myParam.d = value;
break;
}
}
MyFuncParam( MyFuncParamId id, C const& value )
: myId( id )
{
switch ( myId ) {
case myA:
case myB:
case myD:
assert( 0 );
abort();
case myC:
new (&myParam.c) C( value );
break;
}
}
MyFuncParam( MyFuncParamId id, int value )
: myId( id )
{
switch ( myId ) {
case myA:
case myB:
myParam.aOrB = value;
break;
case myC:
assert( 0 );
abort();
case myD:
myParam.d = value;
break;
}
}
MyFuncParam( MyFuncParam const& other )
: myId( other.myId )
{
switch ( myId ) {
case myA:
case myB:
myParam.aOrB = other.myParam.aOrB;
break;
case myC:
new (&myParam.c) C( other.myParam.c );
break;
case myD:
myParam.d = other.myParam.d;
break;
}
}
~MyFuncParam()
{
switch( myId ) {
case myC:
myParam.c.~C();
break;
}
}
MyFuncParam& operator=( MyFuncParam const& ) = delete;
friend class MyFuncParamGroup;
};
class MyFuncRouter
{
MyFuncParamId myId;
public:
MyFuncRouter( MyFuncParamId id ) : myId( id ) {}
MyFuncParam operator=( double value )
{
return MyFuncParam( myId, value );
}
MyFuncParam operator=( C const& value )
{
return MyFuncParam( myId, value );
}
MyFuncParam operator=( int value )
{
return MyFuncParam( myId, value );
}
};
static MyFuncRouter a( myA );
static MyFuncRouter b( myB );
static MyFuncRouter c( myC );
static MyFuncRouter d( myD );
struct MyFuncParamGroup
{
bool aSet;
bool bSet;
bool cSet;
bool dSet;
double a;
double b;
C c;
int d;
MyFuncParamGroup()
: aSet( false )
, bSet( false )
, cSet( false )
, dSet( false )
{
}
void set( MyFuncParam const& param )
{
switch ( param.myId ) {
case myA:
assert( !aSet );
aSet = true;
a = param.myParam.aOrB;
break;
case myB:
assert( !bSet );
bSet = true;
b = param.myParam.aOrB;
break;
case myC:
assert( !cSet );
cSet = true;
c = param.myParam.c;
break;
case myD:
assert( !dSet );
dSet = true;
d = param.myParam.d;
break;
}
}
};
void
myFunc(
MyFuncParam const& p1,
MyFuncParam const& p2,
MyFuncParam const& p3,
MyFuncParam const& p4)
{
MyFuncParamGroup params;
params.set( p1 );
params.set( p2 );
params.set( p3 );
params.set( p4 );
std::cout << "a = " << params.a
<< ", b = " << params.b
<< ", c = " << params.c
<< ", d = " << params.d
<< std::endl;
}
注意:
我在这里使用过C ++ 11。同样的事情可以在早些时候完成
通过将C
中的类型union
替换为C ++的版本
unsigned char c[sizeof( C )];
,向union
添加内容
确保正确对齐(如有必要),以及很多类型
铸造。
使用boost::variant
(而不是。)会更加简单
union
)和boost::optional
(MyFuncParamGroup
)。
我没有提供Boost,所以我做了他们做的大部分工作
明确。 (当然,这会使代码更长。)
我故意使用两个相同类型的参数,
和一个用户定义的类型(C
)与非平凡的构造函数,
以显示如何处理这些。
你可能想要更多的封装,还有更多 错误检查。
但真正的问题是:你真的想走这条路吗?
代码量随着数量的增加而线性增加
参数。和任何体面的编辑,你可以暂时放
从函数声明到右边的参数列表
您的屏幕,并直接填写左侧的参数
在参数声明的旁边。 (在gvim中,我通常会这样做
使用块编辑模式,但:vsplit
也可以
使用。)
答案 5 :(得分:1)
命名参数非常有用,我甚至认为在语言中它们应该是调用函数的唯一方法,除非存在一个明显的参数。
sin(x) // the obvious main parameter
sin(x, unit=DEGREE) // any other must be named
C ++很遗憾没有它们。
更重要的是,C ++缺乏能够实现它们所需的元编程能力。
虽然有一些技巧可以尝试在某种程度上模仿命名参数,即使结果代码看起来几乎合理,但完全不雅的是你需要编写的代码才能获得模拟,并且在C ++中没有办法生成该代码。
我的意思是虽然可以编写一个接受合理模拟的命名参数的函数,但函数本身的代码是可怕的,无法在C ++中自动生成。这意味着没有人会以这种方式编写函数,因此该特征仍然不存在。
我的猜测是由于无知的混合(在C ++发明之前存在,甚至可能在C之前存在)和骄傲(即使在C ++ 11中,语言元编程能力是可悲的和事情琐碎的比如说在编译时枚举一个结构的成员或一个函数的参数是不可能的。)