Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to skip Default Arguments C++?

I have to write constructor with two default parameters.

func(int arg1 , char* arg2 = "arg2", int arg3 = 1) //example

I am provided the scenario where the constructor is called and a value is given to arg1 and arg2 and arg3 is expected to use a default value. Then another object is instantiated and a value is given to arg1 and arg3, and default value for arg2 is expected to be used. Now the problem is, you "can't skip" default parameters is what I'm reading from the text and online. It's saying to order the default paramters from its likliness of being overloaded, but the scenario has one default parameter used while the other isn't. The hints for this question tells me to reorder the parameters/arguments. However, no amount of reordering that I've done seem to be able to resolve this issue.

Also, overloaded constructors can not be used. This has to be done by one constructor.

So how would one do this? I'm stumped and going a bit crazy over this :(

like image 520
user1034846 Avatar asked Nov 24 '11 22:11

user1034846


People also ask

How do you skip arguments in C++?

In C++, display () is used to call without passing any arguments. In the above example, it uses both default parameters are c= '*' and n=8. Display ('#') is used to call only one argument.

Are there default arguments in C?

Default Arguments in C++ A default argument is a value provided in a function declaration that is automatically assigned by the compiler if the calling function doesn't provide a value for the argument. In case any value is passed, the default value is overridden.

Can we pass default arguments to overloaded functions?

No you cannot overload functions on basis of value of the argument being passed, So overloading on the basis of value of default argument is not allowed either. You can only overload functions only on the basis of: Type of arguments. Number of arguments.

Which are the rules for default arguments?

Characteristics for defining the default argumentsThe values passed in the default arguments are not constant. These values can be overwritten if the value is passed to the function. If not, the previously declared value retains. During the calling of function, the values are copied from left to right.


3 Answers

Also, overloaded constructors can not be used. This has to be done by one constructor.

The only reason I can think of for this requirement is that the optional arguments have the same type. In that case, you're stuck and you'll want to look into the named constructor and/or named parameter idioms.

Otherwise, just define the extra constructor. This may involve some duplication wrt. the default values.

Foo(int arg1 , char const *arg2 = "arg2", int arg3 = 1)
{
    construct(arg1, arg2, arg3);
}

Foo(int arg1, int arg3)
{
    construct(arg1, "arg2", arg3);
}
like image 65
Fred Foo Avatar answered Nov 05 '22 06:11

Fred Foo


If you're allowed to pass an empty C-string when you've got no value for the second parameter, you could use a helper functor that'll check arg2 and return default value if it's empty. Something like this:

#define DEFAULT_ARG "arg2"

struct helper_class {
    char* operator()(char* arg)
    {
        if (*arg) return arg; else return DEFAULT_ARG;
    }
} helper;

class func {
    public:
    func(int arg1 , char* arg2 = "arg2", int arg3 = 1) {}
};

int main()
{
    func f1(42, helper(""), 9001);   // default 2nd argument
    func f2(42, helper("Its over 9000!"));
}

Not pretty, I know...

like image 25
jrok Avatar answered Nov 05 '22 07:11

jrok


Peculiar restriction, that there must be only one constructor. Here's the closest I can think of:

#include <iostream>

// cheap and cheerful Boost.Variant
struct StringOrInt {
    char *s;
    int i;
    bool is_string;
    StringOrInt(char *s) : s(s), i(0), is_string(true) {}
    StringOrInt(int i) : s(0), i(i), is_string(false) {}
    bool isInt() { return !is_string; }
    int asInt() { return i; }
    char *asString() { return s; }
};

struct Foo {
    int m1;
    char *m2;
    int m3;
    Foo(int arg1, StringOrInt arg2 = "arg2", int arg3 = 1) : m1(arg1) {
        if (arg2.isInt()) {
            arg3 = arg2.asInt();
            arg2 = "arg2";
        }
        m2 = arg2.asString();
        m3 = arg3;
    }
    void print() {
        std::cout << m1 << " " << m2 << " " << m3 << "\n";
    }
};

int main() {
    Foo(1, "HelloWorld").print();
    Foo(1, 2).print();
}

Note that with GCC this generates warnings, since the conversion from a string literal to non-const char* is deprecated and unwise. But it's what you asked for, and fixing it so that the char* parameters and data member are const char* is easy enough.

A significant weakness is that this doesn't stop you writing Foo(1,2,3). To check that at compile-time I think you need multiple constructors. To check it at runtime, you could make the third parameter into another class, DefaultOrInt, where Default is a type used just for this purpose, supporting only one value used as the default value of arg3. Then if arg2.isInt() is true, check arg3.isInt() is false and if not throw logic_error.

like image 43
Steve Jessop Avatar answered Nov 05 '22 06:11

Steve Jessop