how to skip Default Arguments C++?

2019-02-16 13:36发布

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 :(

4条回答
一纸荒年 Trace。
2楼-- · 2019-02-16 13:52

Right now you can use std::bind to do this kind of operation or in c++14/17 you can use lambda function and accomplish the same.

查看更多
smile是对你的礼貌
3楼-- · 2019-02-16 13:53

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.

查看更多
ゆ 、 Hurt°
4楼-- · 2019-02-16 13:54

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);
}
查看更多
做自己的国王
5楼-- · 2019-02-16 13:56

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...

查看更多
登录 后发表回答