[英]How can we call a function with “parameter=value” in C++?
閱讀代碼時,我們會找到一些這樣的函數。
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 ++如何做到這一點?
C ++本身不支持這種功能,因此您不能只使用任何舊的現有功能。 如果你正在創建自己的API,你可以使用所謂的命名參數成語來模擬它。 鏈接中的示例:
File f = OpenFile("foo.txt")
.readonly()
.createIfNotExist()
.appendWhenWriting()
.blockSize(1024)
.unbuffered()
.exclusiveAccess();
這在C或C ++中是不可能的。
我理解你的痛苦。 我個人認為,有一個函數占用9000個參數是一個糟糕設計的標志,特別是如果它們中的大多數是NULL
或占位符值。 例如,許多POSIX標准化函數采用某種struct
,將所有必要的值累積到一個易於理解的參數中。
不,這不可能。 但是您可以將NULL
值分配給變量,然后將它們作為參數傳遞,如果它有助於您的可讀性!
g_spawn_async(working_directory, argv, envp,flags,child_setup , user_data, child_pid, error);
BOOST參數庫可以幫助您。 它運行良好且便於攜帶....參見http://www.boost.org/doc/libs/1_54_0/libs/parameter/doc/html/index.html
這當然是可能的。 它甚至不是特別困難,但確實涉及很多代碼。 可以使用以下內容:
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 ++來完成,通過更換型C
在union
與unsigned char c[sizeof( C )];
,向union
添加一些東西以確保正確對齊(如果需要),以及大量的類型轉換。
使用boost::variant
(而不是union
)和boost::optional
(在MyFuncParamGroup
)會更簡單。 我沒有Boost可用,所以我做了他們明確做的大部分工作。 (當然,這會使代碼更長。)
我故意使用兩個具有相同類型的參數,以及一個用戶定義的類型( C
)和非平凡的構造函數,以顯示如何處理這些參數。
你可能想要更多的封裝,以及更多的錯誤檢查。
但真正的問題是:你真的想走這條路嗎? 代碼量隨參數數量線性增加。 使用任何不錯的編輯器,您可以暫時將函數聲明中的參數列表放在屏幕右側,並直接在參數聲明的旁邊填寫左側的參數。 (在gvim中,我通常會使用塊編輯模式,但是:vsplit
也可以使用:vsplit
。)
命名參數非常有用,我甚至認為在一種語言中,它們應該是調用函數的唯一方法,除非有一個明顯的參數,如果存在的話。
sin(x) // the obvious main parameter
sin(x, unit=DEGREE) // any other must be named
不幸的是,C ++沒有它們。
更重要的是,C ++缺乏能夠實現它們所需的元編程能力。
雖然有一些技巧可以嘗試在某種程度上模仿命名參數,即使結果代碼看起來幾乎合理,但完全不雅的是你需要編寫代碼以獲得該模擬,並且C ++中沒有辦法生成該代碼。
我的意思是雖然可以編寫一個接受合理模擬的命名參數的函數,但函數本身的代碼是可怕的,不能在C ++中自動生成。 這意味着沒有人會以這種方式編寫函數,因此該函數仍然不存在。
我的猜測是,由於無知的混合(它們在C ++發明之前存在,甚至可能在C之前存在)和驕傲(即使在C ++ 11中,語言元編程能力是可悲的,而且事情是微不足道的,比如說枚舉,因此缺少命名參數在編譯時,結構的成員或函數的參數是不可能的)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.