6

suppose I have:

void f(bool option1 = false, bool option2 =false, bool option3 = false) 
{
     ... 
}

And I want to call:

f(option2=true);

Is this possible in C++?

Chris
  • 28,822
  • 27
  • 83
  • 158
  • I have one, and looked at the documentation, which provided many examples of ordered default specification, but no note that this is not possible; it should be, but knowing C++, it probably isn't. @tadman – Chris May 15 '18 at 19:40
  • 1
    If you're coming from a Python background then your expectations are wrong. C++ is based on C where that's not possible. – tadman May 15 '18 at 19:40
  • I am not coming from Python, I use both C++ and Python, and am a fan of C++... but this should be possible, and a simple "no it isn't possible" would be nice. @tadman – Chris May 15 '18 at 19:42
  • 1
    Nope, you can only make the call by specifying two of the args explicitly. Though, do you really need the first arg to be a default? Maybe for refactoring but it seems like thinking a bit too far ahead. – George May 15 '18 at 19:43
  • 1
    short answer: NO – skeller May 15 '18 at 19:43
  • 3
    You might consider the [Named Parameter Idiom](https://stackoverflow.com/a/2700976/10077). – Fred Larson May 15 '18 at 19:44
  • @George suppose I have a log file. Suppose further, that I would like to place the log file specification next to the primary input, because it is related to the input, rather than the params. Then, suppose I would like to have some toggles at the end related to the behavior of the function. Hence, this makes better organization of inputs impossible--I have to have params spread out according to use, fill in all intermediate params to specify potentially unrelated content, etc. – Chris May 15 '18 at 19:44
  • @bordeo Nothing in C++ is ever simple, there's always lots of nuances and caveats, which is why I first suggested having a good reference. I also mentioned Python because the `f(option2=true)` is exactly how you'd do that in Python, a language that is significantly more flexible when it comes to passing in arbitrary arguments out of order. C++ does not work that way, it can't do it, but the reasons why are a lot more involved to explain, which is why a good reference is absolutely essential. – tadman May 15 '18 at 19:57
  • @tadman except in all cases that I have encountered so far, there is **always** a way to hammer stuff to the point where it is as simple as in other languages--at this point, things tend to be optimal as well (as opposed to the other languages). That is the good thing about C++. However, pretending that it is always perfect is not the way to go--there should be a way to bring things up to a state of simple usability. – Chris May 15 '18 at 19:59
  • 1
    I'm not disagreeing, you can see many examples here of clever C++-isms that let you get what you want but in the C++ way. I'd never argue C++ is perfect, it's got a *lot* of quirks and issues that they're still working to resolve, but I will say that C++ is not something you can absorb fully without a good reference. It's far from intuitive, and innocent mistakes can lead to all sorts of really bad undefined behaviour. Know what you're dealing with, be prepared. Just looking out for you here. – tadman May 15 '18 at 20:09
  • 1
    @tadman yeah, I 100% agree. I try to draft in Python and lay down permanent solutions in C++, once I have the function specs down. – Chris May 15 '18 at 20:24

4 Answers4

14

It is not possible to invoke a function in the manner you suggested in C++. You can emulate named parameters via metaprogramming or simply pass a struct to your function. E.g.

struct options
{
    bool option0{false};
    bool option1{false};
    bool option2{false};
}; 

void f(options opts = {});

C++11 usage:

options opts;
opts.option2 = true;
f(opts);

C++2a usage:

f({.option2=true});
Rakete1111
  • 47,013
  • 16
  • 123
  • 162
Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
4

As alternative, you might use bit flag:

enum FOption
{
    option0 = 1 << 0,
    option1 = 1 << 1,
    option2 = 1 << 2,
};

void f(FOption opt = 0) {
    const bool opt0 = opt & option0;
    const bool opt1 = opt & option1;
    const bool opt2 = opt & option2;
    /*...*/
}

and then use it like:

f(option2);
f(option1 | option2);
Jarod42
  • 203,559
  • 14
  • 181
  • 302
3

I have 12 optional parameters

If all your optional parameters are of type bool, you could use a flag enum:

enum class OptionFlags {
    Option1 = 1,
    Option2 = 2,
    Option3 = 4,
    Option4 = 8
};

inline OptionFlags operator|(OptionFlags a, OptionFlags b) {
    return static_cast<OptionFlags>(static_cast<int>(a) | static_cast<int>(b));
}

Now you can define your function as follows:

void f(OptionFlags f) {
    ...
}

which users would call like this:

f(OptionFlags::Option1 | OptionFlags::Option3); // Option1==true, Option3==true
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
1

No you cannot do that, the names of the parameters are so to speak nonexistant at the call site. There are several ways to work around that. Actually I would already say that 3 bool parameters alone is already a reason do actively do something to avoid confusion for the caller and allow the user to have proper names.

Some might not like this simplistic approach, but it may serve as a starting point:

struct f_params {
    bool a;
    bool b;
    bool c;
    f_params() : a(false),b(false),c(false) {}
    f_params& set_a(bool x) { 
        a = x;
        return *this;
    }
};

The caller may now set only the non-defaults:

f_params x;
x.a = true;
f(x);
// or..
f(f_params().set_a(true));
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185