21

I know it's possible to do something like :

int foo(int a = 0, int b = 1) { return a + b; }

and then use it without the default parameters eg.:

foo();    // a = 0, b = 1 -> 1

or with the last one as default eg.:

foo(2);    // a = 2 and b = 1 default -> 3

But my question is: Is it possible to use the default value for the first argument (a) and give the value of the second (b)

My first thought was doing it like (which doesn't work!):

foo(,2);    // a = 0 default and b = 2

Does a syntax for this exist or is this just not possible ?

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
UNKN57
  • 223
  • 2
  • 8

7 Answers7

21

No, it is not possible in current syntax.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
8

Alternatively from specifying default parameter values you can use multiple function overloads like:

 int foo(int a, int b){return a+b; }
 int foo(int b){return foo(0,b); }     
 int foo(){return foo(0,1); }
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • Wouldn't this have the same effect as `foo(int b=1, int a=0){..}` ? – UNKN57 Oct 03 '16 at 18:53
  • @UNKN57 Well, yes. But a different effect from `int foo(int a=0, int b=1)`. And you can't declare both, because of ambiguity. – πάντα ῥεῖ Oct 03 '16 at 18:55
  • maybe my example wasn't the best. What i wanted was to use the first parameter with the default value and hand over values for arguments to the right (which, as i know now is not possible). – UNKN57 Oct 03 '16 at 19:05
  • @UNKN57 May be your example was oversimplified. There are more variations possible with my proposal regarding disambiguate parameter types. – πάντα ῥεῖ Oct 03 '16 at 19:07
  • @UNKN57: It's unclear to me how this is not doing exactly what you want. If you call `foo(2)` it will be as if you called `foo(0, 2)`. Isn't that exactly what you were trying to do in your example? – Benjamin Lindley Oct 03 '16 at 19:20
  • @Benjamin Lindley Yes i wanted to do this, but i wanted to still be able to call foo(2) for foo(2,1). Obviously this can not work if you try to declare 2 methods. So i thought there might be some special syntax (like my idea with the kommata). – UNKN57 Oct 03 '16 at 19:29
  • @UNKN57 I doubt that kind of syntax will be implemented into c++ soon. – πάντα ῥεῖ Oct 03 '16 at 19:33
  • For the left-out parameters, a special type can be used in the overloads, e.g. https://en.cppreference.com/w/cpp/utility/optional/nullopt_t Then all combinations are possible Of course the parameters themselves can be `std::optional` instead in the first place; then no overloads are needed – Sebastian Mar 14 '23 at 09:20
  • Why not using something like `int foo({.b=2});` where foo accepts an aggregate initialized with: https://en.cppreference.com/w/cpp/language/aggregate_initialization – Fabian Keßler Mar 18 '23 at 10:41
1

It is not possible directly. However, it is possible somehow if you declare a struct for the input parameters that encapsulates the default values and has individual setters:

#include <iostream>
 
struct Foo{
    int a,b;
    Foo() : a(0),b(1) {};
    Foo setA(int x) { a=x; return *this;}
    Foo setB(int x) { b=x; return *this;}
};
 
void foo(Foo f = Foo()){ std::cout << f.a << "  " << f.b << std::endl; }
 
int main() {
    foo();                // uses default values for a and b
    foo(Foo().setA(3));   // uses default value for b
    foo(Foo().setB(5));   // uses default value for a
}
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • Why not combining Aggregate initialisation with an aggregate as function parameter? https://en.cppreference.com/w/cpp/language/aggregate_initialization – Fabian Keßler Mar 18 '23 at 10:37
  • @FabianKeßler there is no "why not". The point of the answer is just to use a custom struct – 463035818_is_not_an_ai Mar 18 '23 at 12:50
  • an aggregate is also a custom struct, but it does not require the setters: https://godbolt.org/z/9556jqard – Fabian Keßler Mar 18 '23 at 13:04
  • @FabianKeßler I know, if it works for you go for it. This answer is from 2016 when c++20 was not widely available. Consider this: https://godbolt.org/z/7hK33dnac – 463035818_is_not_an_ai Mar 18 '23 at 13:07
  • Yes, I know, that this is a c++20 feature. I am only curious, why this question was shown on the front page of my feed. Nevertheless, you could/can add the c++ aggregate version for c++20 users to your answer. – Fabian Keßler Mar 18 '23 at 14:49
1

Once we provide a default value for a parameter, all subsequent parameters must also have default values. For example,

// Invalid
void add(int a, int b = 3, int c, int d);

// Invalid
void add(int a, int b = 3, int c, int d = 4);

// Valid
void add(int a, int c, int b = 3, int d = 4);
1

Though still not possible the way OP expects, there is since a way to mimic this behaviour using std::optional.

Instead of passing int as arguments, pass optional<int> with default value of {}:

int foo(std::optional<int> in_a = {}, std::optional<int> in_b = {});

Then replace in the function body by the "real" default values if the user did not provide a value ({} or std::nullopt was passed):

int foo(std::optional<int> in_a = {}, std::optional<int> in_b = {})
{
    const auto a = in_a.value_or(default_value_for_a);
    const auto b = in_b.value_or(default_value_for_b);

    return a + b;
}

For example, assuming you want default value of a but not b, you now do:

foo({}, value_for_b);

This generalises well when more parameters are added. The only restriction is that you must be able to put the type in optional, which has some restrictions regarding this.

Erel
  • 512
  • 1
  • 5
  • 14
0

I know that it is not really an answer to your question, but you could try to use boost named parameters. It might be useful for your use case.

erikzenker
  • 752
  • 5
  • 18
  • 1
    i hadn't had an actual usecase. Just aked this myself while learning (im an absolute c++ newbie). But your link seems very helpful! – UNKN57 Oct 03 '16 at 18:45
-2

no it is not possible first parameter has to be filled by some value