optional argument of a function

How to have optional argument of a function, being explicitly meant so with condition rule:

. if argument/parameter exists, it's as is supposed to be

. if it does not, the function does not outright have it, as if its declaration having the total number of argument substracted with 1, which means without that argument/parameter at all

without getting double function writing by overload fn.
it's at least 95 lines
Last edited on
1
2
3
4
5
6
7
8
9
10
#include <iostream>

void foo(int) { std::cout << "foo(int)\n"; }
void foo() { std::cout << "foo()\n"; }

int main()
{
  foo(2); // calls foo(int)
  foo();  // calls foo()
}
Last edited on
Without getting double function writing by overload fn.

Either you added this in later, or I misread:

Your other option is to create a set of overloads via default arguments:
1
2
3
4
5
6
7
8
9
#include <iostream>

void foo(int x = 0) { std::cout << x << '\n'; }

int main()
{
  foo(2); // calls foo(2)
  foo();  // calls foo(0)
}
Your other option is to create a set of overloads via default arguments

Default arguments don't create a set of overloads.
mbozzi wrote:
or I misread:
You didn't misread it.
@dutch Right, thanks. There is still only one function.
Last edited on
@mbozzi, Default args are a little weird. As you know, they need to appear in the header file so that the compiler can fill in the value in the actual call with only the info in the header. I've noticed that the standard library seems to be removing default arguments in some places. I wonder what the reason for that is and what best practices have to say about it.
> How to have optional argument of a function, being explicitly meant so with condition rule:
> if argument/parameter exists, it's as is supposed to be
> if it does not, the function does not outright have it,

Use a parameter pack to represent the optional arguments, perhaps.
https://en.cppreference.com/w/cpp/language/parameter_pack

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
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <typeinfo>

struct print
{
    template < typename T > const print& operator<< ( T&& v ) const
    {
        std::cout << "      " << v << "  (type: " << typeid(T).name() << ")\n" ;
        return *this ;
    }
};

template < typename... OPTIONAL_ARGS > // 
void foo( int a, const char* b, OPTIONAL_ARGS&& ... optional_args /* zero or more optional  arguments */ )
{
    std::cout << "foo:\n  a == " << a
              << "  b == " << ( b ? b : "nullptr" ) << '\n' ;

    std::cout << "  #additional args: " << sizeof...(optional_args) << '\n' ;
    ( print() << ... << optional_args ) ;

    std::cout << "\n-----------------\n" ;
}

struct xyz
{
    int v = 0 ;
    friend std::ostream& operator<< ( std::ostream& stm, xyz x )
    { return stm << "::xyz{" << x.v  << '}' ; }
};

int main()
{
    foo( 23, "abcd" ) ;
    foo( 7890, "ijkl", 1234, 56.78, xyz{9} ) ;
    foo( 12345, "mnop", 56789, 0.1234, "qrst", +"uvwx",  xyz{56789} ) ;
}

http://coliru.stacked-crooked.com/a/3dff18e574c3c6d8
JLBorges, could you please explain me how does row 20 work?

( print() << ... << optional_args ) ;

What are those round parentheses and why we need them?
It is a fold-expression which came with C++17. https://en.cppreference.com/w/cpp/language/fold

A fold-expression always starts with an open parenthesis and ends with a closing parenthesis;
the parentheses are an integral part of the fold-expression.

What we have is 4) binary left fold https://en.cppreference.com/w/cpp/language/fold#Explanation
where init I is an anonymous object of type print
Last edited on
Thank you a lot, JLBorges.
So many thing to learn…
Thanks great worthwhile tips
dutch wrote:
I've noticed that the standard library seems to be removing default arguments in some places. I wonder what the reason for that is and what best practices have to say about it.

I haven't noticed any such change, so I don't know. Do you have any specific example in mind?

@mbozzi, I've noticed it mostly in ctors. Here's a couple of examples:

On this page from cppreference for the basic_string ctor, form number 3 before C++17 has a default argument for count, but since C++17 it has two separate ctors.

https://en.cppreference.com/w/cpp/string/basic_string/basic_string

On these pages for vector and list, form number 3 has a default argument for value which was removed in C++11.

https://en.cppreference.com/w/cpp/container/vector/vector
https://en.cppreference.com/w/cpp/container/list/list

On this page for basic_istringstream, form number 2 has it's default argument removed for C++11.

https://en.cppreference.com/w/cpp/io/basic_istringstream/basic_istringstream
On this page from cppreference for the basic_string ctor, form number 3 before C++17 has a default argument for count, but since C++17 it has two separate ctors.
Constructors for containers in the standard library come in pairs. Typically, one constructor takes an allocator argument and the other doesn't. In this case, one was missing. The new constructor allows
std::string(str, pos, alloc)
instead of the equivalent, more verbose
std::string(str, pos, std::string::npos, alloc).

The change is traced to LWG issue 2583:
https://wg21.link/lwg2583

On these pages for vector and list, form number 3 has a default argument for value which was removed in C++11.
For both vector and list, the addition of constructor 4 would cause ambiguity if the default arguments remained; there is a difference in semantics between the two overloads (in both cases, #4 doesn't make copies).

On this page for basic_istringstream, form number 2 has it's default argument removed for C++11.
basic_istringstream had an explicit default constructor (i.e., #2).

The change was proposed for C++11 by P0935:
https://wg21.link/p0935 (grep that document for istringstream.)
Last edited on
@mbozzi, Thank you. That explains it. And that wg21.link redirect site is interesting in itself. :)
Topic archived. No new replies allowed.