简体   繁体   English

如何在C ++中调用带有“parameter = value”的函数?

[英]How can we call a function with “parameter=value” in C++?

When reading codes, we will find some functions like this. 阅读代码时,我们会找到一些这样的函数。

g_spawn_async(NULL, new_argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL);

I think nobody can figure out what is the meaning of every parameter. 我想没有人能弄清楚每个参数的含义是什么。 In order to understand the code, we have to find the declaration of the function. 为了理解代码,我们必须找到函数的声明。

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);

How can we call a function like the following format in C++? 我们如何在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);

I think this one will be more readable and I can understand the code without looking for the declaration of the function. 我认为这个将更具可读性,我可以理解代码而无需查找函数的声明。

I know Python can do this. 我知道Python可以做到这一点。 How can C++ do this? C ++如何做到这一点?

C++ doesn't support this natively, so you can't do it with just any old existing function. C ++本身不支持这种功能,因此您不能只使用任何旧的现有功能。 If you're creating your own API though, you can use what's called the Named Parameter Idiom to emulate it. 如果你正在创建自己的API,你可以使用所谓的命名参数成语来模拟它。 The example from the link: 链接中的示例:

File f = OpenFile("foo.txt")
           .readonly()
           .createIfNotExist()
           .appendWhenWriting()
           .blockSize(1024)
           .unbuffered()
           .exclusiveAccess();

This is not possible in C or C++. 这在C或C ++中是不可能的。

I understand your pains with this. 我理解你的痛苦。 I personally think that it is a sign of bad design to have a function take over 9000 arguments, especially if most of them are NULL or placeholder values. 我个人认为,有一个函数占用9000个参数是一个糟糕设计的标志,特别是如果它们中的大多数是NULL或占位符值。 Many POSIX-standardized functions for example take some kind of struct that accumulates all necessary values into one, easy to understand argument. 例如,许多POSIX标准化函数采用某种struct ,将所有必要的值累积到一个易于理解的参数中。

No, this can't be done. 不,这不可能。 But you can assign the NULL values to the variables and then pass them as parameters if it helps with your readability! 但是您可以将NULL值分配给变量,然后将它们作为参数传递,如果它有助于您的可读性!

g_spawn_async(working_directory, argv, envp,flags,child_setup , user_data, child_pid, error);

The BOOST parameter library can help you. BOOST参数库可以帮助您。 It works well and is portable.... See http://www.boost.org/doc/libs/1_54_0/libs/parameter/doc/html/index.html 它运行良好且便于携带....参见http://www.boost.org/doc/libs/1_54_0/libs/parameter/doc/html/index.html

It's certainly possible. 这当然是可能的。 It's not even particularly difficult, but it does involve a lot of code. 它甚至不是特别困难,但确实涉及很多代码。 Something like the following could be used: 可以使用以下内容:

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;
}

Notes: 笔记:

  1. I've used C++11 here. 我在这里使用过C ++ 11。 The same thing can be done in earlier versions of C++, by replacing the type C in the union with unsigned char c[sizeof( C )]; 同样的事情可以在早期版本的C ++来完成,通过更换型Cunionunsigned char c[sizeof( C )]; , adding something to the union to ensure correct alignment (if necessary), and a lot of type casting. ,向union添加一些东西以确保正确对齐(如果需要),以及大量的类型转换。

  2. This would be a lot simpler with boost::variant (instead of the union ) and boost::optional (in MyFuncParamGroup ). 使用boost::variant (而不是union )和boost::optional (在MyFuncParamGroup )会更简单。 I didn't have Boost available, so I did most of what they do explicitly. 我没有Boost可用,所以我做了他们明确做的大部分工作。 (Which of course, makes the code a lot longer.) (当然,这会使代码更长。)

  3. I've intentionally used two parameters with the same type, and a user defined type ( C ) with non-trivial constructors, to show how these are handled. 我故意使用两个具有相同类型的参数,以及一个用户定义的类型( C )和非平凡的构造函数,以显示如何处理这些参数。

  4. You'd probably want a bit more encapsulation, and a bit more error checking. 你可能想要更多的封装,以及更多的错误检查。

But the real question is: do you really want to go this route? 但真正的问题是:你真的想走这条路吗? The amount of code increases linearly with the number of parameters. 代码量随参数数量线性增加。 And with any decent editor, you can temporarily put the parameter list from the function declaration to the right of your screen, and fill out the parameters to the left, directly along side of the parameter declaration. 使用任何不错的编辑器,您可以暂时将函数声明中的参数列表放在屏幕右侧,并直接在参数声明的旁边填写左侧的参数。 (In gvim, I'll usually use block editing mode for this, but :vsplit can also be used.) (在gvim中,我通常会使用块编辑模式,但是:vsplit也可以使用:vsplit 。)

Named parameters are very useful and I was even considering that in a language they should be the only way to call a function except for a single obvious parameter if that is present. 命名参数非常有用,我甚至认为在一种语言中,它们应该是调用函数的唯一方法,除非有一个明显的参数,如果存在的话。

sin(x)               // the obvious main parameter
sin(x, unit=DEGREE)  // any other must be named

C++ unfortunately doesn't have them. 不幸的是,C ++没有它们。

More importantly C++ lacks the metaprogramming ability needed to be able to implement them. 更重要的是,C ++缺乏能够实现它们所需的元编程能力。

While there are tricks that can try to somewhat mimic named parameters and even if the resulting code can look almost reasonable, what is totally indecent is the code you need to write to get that simulation and that there is no way in C++ to generate that code. 虽然有一些技巧可以尝试在某种程度上模仿命名参数,即使结果代码看起来几乎合理,但完全不雅的是你需要编写代码以获得该模拟,并且C ++中没有办法生成该代码。

What I mean is that while it's possible to write a function accepting named parameters emulated reasonably, the code for the function itself is hideous and cannot be automatically generated in C++. 我的意思是虽然可以编写一个接受合理模拟的命名参数的函数,但函数本身的代码是可怕的,不能在C ++中自动生成。 This means that no one will write functions that way so the feature is still not present. 这意味着没有人会以这种方式编写函数,因此该函数仍然不存在。

My guess is that named parameters are missing because of a mix of ignorance (they existed way before C++ was invented, probably even before C) and of pride (even in C++11 the language metaprogramming abilities are pathetic and things trivial like say enumerating at compile time the members of a structure or the parameters of a function is impossible). 我的猜测是,由于无知的混合(它们在C ++发明之前存在,甚至可能在C之前存在)和骄傲(即使在C ++ 11中,语言元编程能力是可悲的,而且事情是微不足道的,比如说枚举,因此缺少命名参数在编译时,结构的成员或函数的参数是不可能的)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在C ++中使用参数列表调用函数? - How can I call a function using parameter list in c++? C++ gmock - 我们如何在单元测试 cpp 文件中读取/获取 cpp 文件的函数的参数值 - C++ gmock - How we can read/get the parameter value of a function of cpp file in unit test cpp file 函数如何修改C ++中按值传递的参数? - How can a function modify a parameter passed in by value in C++? 在C ++中,如何在不使用友元函数的情况下通过对象调用私有函数? - In C++ how can we call private function through an object without using friend function? 如何调用接受来自 C# 的 stringstream 类型参数的 C++ DLL 函数? - How can I call a function of a C++ DLL that accepts a parameter of type stringstream from C#? 我们如何在c ++中检查模板参数的类型? - How can we check the type of the template parameter in c++? 我们可以用C ++制作一个映射,将值作为键的函数吗? - Can we make a map in C++, with the value as a function of key? 如何在Linux中使用c或c ++而不使用system()或exec()函数的情况下调用pwd或ls -l之类的系统函数? - how we can call a system function like pwd or ls -l without using system() or exec() function using c or c++ in linux? 如何在C ++中调用函数 - How can I call a function in C++ C++ isPrime function: How can I return a Boolean value from a function that takes an integer parameter? - C++ isPrime function: How can I return a Boolean value from a function that takes an integer parameter?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM