Default arguments and omitting only some of them

Hi!

I am trying to figure out what's the best way to accomplish something like this:
1
2
3
void function(t1 a=0,t2 b=0){/*...*/};
t2 value;
function(value);

That would throw a compile error, since the first argument that is being passed to the function (value) is considered the first argument in the declaration (a), which is of type t1. So, is there a way to force my function to consider value as the second argument instead of the first one?
I am aware that this could be done using overloading, but the larger the amount of arguments, the larger amount of possibilities, so it might end up with a huge list of overloads.
The best case scenario would be being able to set things like:
1
2
void function(t1 a=16,t1 b=0,t2 c=1){/*body*/};
function(b=3,a=0);
but I'm not aware of such feature in C++.
Would it be possible to design some sort of macro system to take care of this?

Thanks.
Crude, but:
1
2
3
4
5
6
7
8
9
10
11
12
13
struct T42 {
  t1 a {16};
  t1 b {0};
  t2 c {1};
};

void function( T42 p );


T42 x;
x.b = 3;
x.c = 0;
function( x );
Something I often do to deal with this problem is simply to define multiple functions:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void functionNoArgs()
{
t1 a=0;
t2 b=0;
/*…*/
};
void functionBothArgs(t1 a,t2 b)
{
/*…*/
};
void functionT1Args(t1 a)
{
t2 b=0;
/*…*/
};
void functionT2Args(t2 b)
{
t1 a=0;
/*…*/
};

t2 value;
function(value);
Function overloading is the proper way to handle it:

1
2
3
4
5
6
7
8
9
void foo( T1 a, T2 b = BAR )
{
  ...
}

void foo( T2 b )
{
  return foo( BAZ, b );
}

If you cannot make distinct function signatures based on type (say, T1==T2), then your only other option is the named parameter idiom. It's fun!

http://www.parashift.com/c++-faq/named-parameter-idiom.html

Hope this helps.
Thanks very much to all of you.

The named parameter idiom is just what I was looking for. I never thought about using the functions of a class and chaining to do this. Absolutely brilliant.
Example program for named parameter using method chaining:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <iostream>

class a_rec
{
  private:
    int _dm1;
    int _dm2;
    int _dm3;
    int _dm4;
  public:
    a_rec();
    a_rec(int, int, int, int);
    void print();
    a_rec& dm1(int);
    a_rec& dm2(int);
    a_rec& dm3(int);
    a_rec& dm4(int);
};

inline a_rec::a_rec()
{
  _dm1 = _dm2 = _dm3 = _dm4 = 0;
}

inline a_rec::a_rec(int ival1, int ival2, int ival3,int ival4)
{
  _dm1 = ival1;
  _dm2 = ival2;
  _dm3 = ival3;
  _dm4 = ival4;
}

inline void a_rec::print()
{
  std::cout << std::endl << "A record" << std::endl;
  std::cout << "_dm1: " << _dm1 << std::endl;
  std::cout << "_dm2: " << _dm2 << std::endl;
  std::cout << "_dm3: " << _dm3 << std::endl;
  std::cout << "_dm4: " << _dm4 << std::endl;
}

inline a_rec& a_rec::dm1(int ival)
{
  _dm1 = ival;
  return *this;
}

inline a_rec& a_rec::dm2(int ival)
{
  _dm2 = ival;
  return *this;
}

inline a_rec& a_rec::dm3(int ival)
{
  _dm3 = ival;
  return *this;
}

inline a_rec& a_rec::dm4(int ival)
{
  _dm4 = ival;
  return *this;
}

int main()
{  
 a_rec r1;
 r1.print();
 
 a_rec r2(1,2,3,4);
 r2.print();
 
 a_rec r3 = a_rec().dm1(0).dm2(0).dm3(0).dm4(0);
 r3.print();
 
 a_rec r4 = a_rec().dm4(4).dm3(3).dm1(1).dm2(2);
 r4.print();

 return 0;
}
The named parameter idiom is cool!
Meh. I always thought it was atrocious. Like a hack to weasel in functionality that isn't very C++-like.

But if it works, it works I guess...
Hi, I've been trying this method, but I ran into an issue. Can anyone help me sea with this? When I declare a variable, the compiler seems to want me to stop after the constructor. In other words, I'm not getting the option to call these functions in some syntax contexts. For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
ClassA 
{
public:
       ClassA& addLongStringPair(long _long,string _string);
    private:
        map<long, string>longMappedStrings;
        map<string, long>stringMappedLongs;
        set<string>stringSet;
        set<long>longSet;
}
ClassA& ClassA::addLongStringPair(long _long,string _string)
{
        stringSet.insert(_string);
        longSet.insert(_long);
        longMappedStrings.insert(make_pair(_long,_string));
        stringMappedLongs.insert(make_pair(_string,_long));
        return *this;
}
ClassB
{
    public:
    static ClassA&getType();
}
ClassA&ClassB::getType()
{
        static ClassA myType.addLongStringPair(abbreviation,"abbreviation").addLongStringPair(name,"name").addLongStringPair(number,"number").addLongStringPair(numberOfNameOptions,"numberOfNameOptions");
        return myType;
}

In the case above, I get the compiler error:

error: expected ';' at end of declaration

where it want's me to stop at static ClassA myType;
and then call those functions on another line.
I suppose I could write a static bool to keep that second line from being called more than once, but is there a way to get the functionality I'm looking for?
Thanks
Nevermind, I found my syntax was not quite the same as that mentioned above:
My fix:
 
static ClassA  myType= ClassA().addLongStringPair(abbreviation,"abbreviation").addLongStringPair(name,"name").addLongStringPair(number,"number").addLongStringPair(numberOfNameOptions,"numberOfNameOptions");        

This now works for me.
Last edited on
smcguffee wrote:
Hi, I've been trying this method, but I ran into an issue.

If you're referring to the named parameter idiom you are not using it.

std::initializer_list would be more suitable for this task.

Ignoring the fact that the set members are completely redundant because you get the same functionality from the map members you are already using, this might look something like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <string>
#include <map>
#include <set>
#include <initializer_list>

using namespace std;

class A
{
public:
    struct pair_type    // or use std::pair
    {
        long val;
        std::string desc;
    };

    A(initializer_list<A::pair_type>);

private:
    map<long, string> _valueMap;
    map<string, long> _descriptionMap;
    set<string> _descriptions;
    set<long> _values;
};

A::A(initializer_list<A::pair_type> l)
{
    for (auto & elem : l)
    {
        _valueMap.emplace(elem.val, elem.desc);
        _descriptionMap.emplace(elem.desc, elem.val);
        _descriptions.emplace(elem.desc);
        _values.emplace(elem.val);
    }
}


class B
{
    enum { abbreviation, name, number, numberOfNameOptions };

public:
    static A& getType();
};

A& B::getType()
{
    static A a =
    {
        { abbreviation, "abbreviation" },
        { name, "name" },
        { number, "number" },
        { numberOfNameOptions, "numberOfNameOptions" }
    };

    return a;
}


http://ideone.com/VwqbqS
Topic archived. No new replies allowed.