簡體   English   中英

如何在C ++中調用帶有“parameter = value”的函數?

[英]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;
}

筆記:

  1. 我在這里使用過C ++ 11。 同樣的事情可以在早期版本的C ++來完成,通過更換型Cunionunsigned char c[sizeof( C )]; ,向union添加一些東西以確保正確對齊(如果需要),以及大量的類型轉換。

  2. 使用boost::variant (而不是union )和boost::optional (在MyFuncParamGroup )會更簡單。 我沒有Boost可用,所以我做了他們明確做的大部分工作。 (當然,這會使代碼更長。)

  3. 我故意使用兩個具有相同類型的參數,以及一個用戶定義的類型( C )和非平凡的構造函數,以顯示如何處理這些參數。

  4. 你可能想要更多的封裝,以及更多的錯誤檢查。

但真正的問題是:你真的想走這條路嗎? 代碼量隨參數數量線性增加。 使用任何不錯的編輯器,您可以暫時將函數聲明中的參數列表放在屏幕右側,並直接在參數聲明的旁邊填寫左側的參數。 (在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM