views:

206

answers:

7

I was wondering if in C/C++ language it is possible to pass arguments to function in key-value form. For example in python you can do:

def some_function(arg0 = "default_value", arg1):
    # (...)

value1 = "passed_value"
some_function(arg1 = value1)

So the alternative code in C could look like this:

void some_function(char *arg0 = "default_value", char *arg1)
{
    ;
}

int main()
{
    char *value1 = "passed_value";
    some_function(arg1 = value1);
    return(0);
}

So the arguments to use in some_function would be:

arg0 = "default_value"

arg1 = "passed_value"

Any ideas?

+2  A: 

No, you cannot pass parameters by name in C or C++.

Both languages support default arguments to the trailing parameters in a function. That is, any argument to a function may have a default value, but all subsequent arguments after the first default value is found must also have default values.

For example, the following are all valid:

void f(int a, int b = 0);
void g(double a = 1, double b = 2);
void h(int a = 3, int b = 2, int c = 1, int d = 0);
void i(float a, float b, float c = 1, float d = 2);

But the none of the following are valid:

void j(int a = 1, int b);
void k(int a, int b = 1, int c);
void l(int a = 2, int b = 1, int c);

The reason is simple: Since you cannot pass parameters by name in C and C++, the only way to know which parameters to use the defaults and which to use the passed values is by assigning the passed values to the parameters in order and then using the defaults (in order) for anything left over.

So, the following calls are valid using the functions above:

f(0); // calls f(0, 1);
g(); // calls g(1,2);
g(10); // calls g(10,2);
h(); // calls h(3,2,1,0);
h(1,2); // calls h(1,2,1,0);
SoapBox
"Both languages support default arguments to the trailing parameters in a function." -> No, C doesn't have default arguments.
Johannes Schaub - litb
C does *not* allow default parameters.
el.pescado
+6  A: 

You can emulate this in C++ with this:

struct params {
   string foo_;
   double bar_;
   short  xxx_;
   params() : foo_("123"), bar_(3.1415), xxx_(42) {} // default parameters
   params& foo(string s) {foo_=s;return *this;}
   params& bar(double x) {bar_=x;return *this;}
   params& xxx(short x) {xxx_=x;return *this;}
};

void some_function(params const & p);

int main() {
   some_function(params().bar(99.9).xxx(23));
}

But IMHO it's not worth the effort. Too much boiler plate.

If I remember correctly Stroustrup's book "Design and Evolution of C++" contains a section that discusses this feature request of "named arguments". The conclusion was something along the lines of: not a good idea. Check it out if you want details.

sellibitze
This approach of using a params struct is known as the "named parameter idiom" in C++.
Josh Kelley
+1  A: 

Named arguments are not supported in C, but you could emulate named parameters it using variadic function (though you loose type safety):

#include <stdarg.h>

void do_sth (int foo, ...)
{
    int baz = 7;             /* "baz" argument */
    const char *xyz = "xyz"; /* "xyz" argument */

    /* Parse named parameters */
    va_list ap;
    va_start (ap, foo);
    for (;;) {
        const char *key = va_arg (ap, char *);
        if (key == NULL) {
            /* Terminator */
            break;
        } else if (strcmp (key, "baz") == 0) {
            baz = va_arg (ap, int);
        } else if (strcmp (key, "xyz") == 0) {
            xyz = va_arg (ap, char *);
        } else {
            /* Handle error */
        }
    }
    va_end (ap);

    /* do something useful */
}

do_sth (1, NULL);                             // no named parameters
do_sth (2, "baz", 12, NULL);                  // baz = 12
do_sth (3, "xyz", "foobaz", NULL);            // xyz = "foobaz"
do_sth (4, "baz", 12, "xyz", "foobaz", NULL); // baz = 12, xyz = "foobaz"

Just remember to end optional arguments list with NULL. You could also use some ENUM as keys instead of character strings.

This technique is used, for exapmle, in GTK+:

el.pescado
Who downvoted absolutely valid answer with no apparent reason? +1 from me.
qrdl
A: 

C++ only solution: You could use boost::any, std::map and std::string to create an object with the posible arguments.

#include <iostream>
#include <map>
#include <string>

#include "boost/any.hpp"

using namespace std;

void variableArguments(map<string, boost::any> arguments){
    cout << ">>> variableArguments begins" << endl;

    if(arguments.find("intParameter") != arguments.end()){
    cout << "Found int parameter: " 
         << boost::any_cast<int>(arguments["intParameter"]) << endl;
    }

    if(arguments.find("stringParameter") != arguments.end()){
    cout << "Found string parameter: " 
         << boost::any_cast<string>(arguments["stringParameter"]) << endl;
    }

    cout << "<<< variableArguments ends" << endl;

}

int main(int argc, char *argv[])
{

    map<string, boost::any> argMap;
    argMap["intParameter"] = 5;
    argMap["stringParameter"] = string("MyString");

    variableArguments(argMap);

    argMap.erase(argMap.find("intParameter"));

    variableArguments(argMap);

    return 0;
}
TheOm3ga
+2  A: 

This is not available in vanilla C or C++. However, there is a C++ Boost Library that lets you do this for functions you write: Boost.Parameter. To borrow one of their examples, its usage is sort of like this:

myclass x("bob", 3);                     // positional
myclass y(_index = 12, _name = "sally"); // named
myclass z("june");                       // positional/defaulted

Implementing this for your functions does look somewhat involved, however. You may decide it isn't worth the effort.

+6  A: 

Here's a C99 solution using compound literals and variadic macros:

#include <stdio.h>

#define some_func(...) some_func_((struct some_func_args_){ __VA_ARGS__ })

struct some_func_args_
{
    const char *arg1;
    const char *arg2;
};

static void some_func_(struct some_func_args_ args)
{
    if(!args.arg1) args.arg1 = "default";
    printf("---\narg1 = %s\narg2 = %s\n", args.arg1, args.arg2);
}

int main(void)
{
    some_func("foo", "bar");
    some_func(.arg1 = "spam");
    some_func(.arg2 = "eggs");
    return 0;
}
Christoph
I like this. Very creative and clean.
nategoose
Note though that with this method it is impossible to differentiate a zero / NULL argument from an omitted argument.
caf
A: 
#define call_foo(...) \
   do { \
      int first; \
      int second; \
      int third;  \
      (__VA_ARGS__); \
      foo(first, second, third); \
   } while (0)

....

int main(void) {
   call_foo(first=9, third=5, second=3);
}

Getting return values in a non-clunky manner is more difficult.

This would allow you to do very silly things (which I hate) such as specify default values for your arguments:

#define call_foo(...) \
   do { \
      int first = default_first; \
      int second; \
      int third;  \
      (__VA_ARGS__); \
      foo(first, second, third); \
   } while (0)

This will fail if you do:

   int first = 9;
   call_foo(first=first, third=5, second=3);

because in the macro expansion the first=first will mean initialize the local first with itself. I thought about trying to get around this with preprocessor concatenation, but that gets more complicated. You would have to list the same number of macro parameters as function parameters.

#define call_foo(x, y , z) \
   do { \
      int call_foo_first; \
      int call_foo_second; \
      int call_foo_third;  \
      call_foo_##x;   \
      call_foo_##y;   \
      call_foo_##z;   \
      foo(call_foo_first, call_foo_second, call_foo_third); \
   } while (0)

The call_foo_##x; line would turn into call_foo_first=first; if called in the previous example, so each symbol has it's own unique name. This makes the default argument trick more awkward because you'd have to specify something to fill that spot in the macro argument list.

If the macro were defined with a default argument for first then:

call_foo(first, third=7, second=8);

This forces you to list all parameters (or at least something that results in legal C -- you could have listed second twice, but you could have done that anyway) in order use this macro.

I think you should be able to extend the last version of this for variable argument listed macros/functions, but the optional parameters would still have to be passed at the end of the list and you would have to use up all of the mandatory spots before you got to the optional arguments.

nategoose