How to pass optional arguments to a method in C++ ?
Any code snippet...
Here is an example of passing mode as optional parameter
void myfunc(int blah, int mode = 0)
{
if (mode == 0)
do_something();
else
do_something_else();
}
you can call myfunc in both ways and both are valid
myfunc(10); // Mode will be set to default 0
myfunc(10, 1); // Mode will be set to 1
An important rule with respect to default parameter usage:
Default parameters should be specified at right most end, once you specify a default value parameter you cannot specify non default parameter again.
ex:
int DoSomething(int x, int y = 10, int z) -----------> Not Allowed
int DoSomething(int x, int z, int y = 10) -----------> Allowed
It might be interesting to some of you that in case of multiple default parameters:
void printValues(int x=10, int y=20, int z=30)
{
std::cout << "Values: " << x << " " << y << " " << z << '\n';
}
Given the following function calls:
printValues(1, 2, 3);
printValues(1, 2);
printValues(1);
printValues();
The following output is produced:
Values: 1 2 3
Values: 1 2 30
Values: 1 20 30
Values: 10 20 30
Reference: http://www.learncpp.com/cpp-tutorial/77-default-parameters/
To follow the example given here, but to clarify syntax with the use of header files, the function forward declaration contains the optional parameter default value.
myfile.h
void myfunc(int blah, int mode = 0);
myfile.cpp
void myfunc(int blah, int mode) /* mode = 0 */
{
if (mode == 0)
do_something();
else
do_something_else();
}
With the introduction of std::optional in C++17 you can pass optional arguments:
#include <iostream>
#include <string>
#include <optional>
void myfunc(const std::string& id, const std::optional<std::string>& param = std::nullopt)
{
std::cout << "id=" << id << ", param=";
if (param)
std::cout << *param << std::endl;
else
std::cout << "<parameter not set>" << std::endl;
}
int main()
{
myfunc("first");
myfunc("second" , "something");
}
Output:
id=first param=<parameter not set>
id=second param=something
See https://en.cppreference.com/w/cpp/utility/optional
Use default parameters
template <typename T>
void func(T a, T b = T()) {
std::cout << a << b;
}
int main()
{
func(1,4); // a = 1, b = 4
func(1); // a = 1, b = 0
std::string x = "Hello";
std::string y = "World";
func(x,y); // a = "Hello", b ="World"
func(x); // a = "Hello", b = ""
}
Note : The following are ill-formed
template <typename T>
void func(T a = T(), T b )
template <typename T>
void func(T a, T b = a )
With commas separating them, just like parameters without default values.
int func( int x = 0, int y = 0 );
func(); // doesn't pass optional parameters, defaults are used, x = 0 and y = 0
func(1, 2); // provides optional parameters, x = 1 and y = 2
Typically by setting a default value for a parameter:
int func(int a, int b = -1) {
std::cout << "a = " << a;
if (b != -1)
std::cout << ", b = " << b;
std::cout << "\n";
}
int main() {
func(1, 2); // prints "a=1, b=2\n"
func(3); // prints "a=3\n"
return 0;
}
Jus adding to accepted ans of #Pramendra , If you have declaration and definition of function, only in declaration the default param need to be specified
Related
Thank you all, I didn't even know about user-defined conversion function and how it works.
Why is it possible to use std::reference_wrapper<int>::operator+=, if such an operator does not exist, are there some implicit conversions?
#include <iostream>
#include <functional>
#include <boost/type_index.hpp>
using boost::typeindex::type_id_with_cvr;
template <typename C>
void test(C c)
{
c += 1;
}
int main()
{
int a = 3;
test(a);
std::cout << a << std::endl;
test(std::ref(a));
std::cout << a << std::endl;
}
Output:
3
4
To check that template works perfectly fine:
void test_2(std::reference_wrapper<int> c)
{
c += 1;
}
int main()
{
int a = 3;
test_2(std::ref(a));
std::cout << a << std::endl;
}
Output:
4
Still works as before. How is that possible?
Funny thing, that in auto d = b + c, d has an integer type.
int main()
{
auto b = std::ref(a);
auto c = std::ref(a);
auto d = b + c;
std::cout << type_id_with_cvr<decltype(d)>).pretty_name() << std::endl;
}
Output:
int
It's because it's implicitly convertible to a reference to T:
/* constexpr [c++20] */ operator T& () const noexcept;
In your case, it's implicitly convertible to an int&.
This ability to be implicitly convertible to an int& is also what would make it possible for you to define your function to take an int& while passing it a std::reference_wrapper<int>:
void test_2(int& c) // <--+
{ // |
c += 1; // |
} // |
int main() { // |
// ... // |
test_2(std::ref(a)); // >--+
}
According to the C++ 17 Standard (10.3.3 The using declaration)
1 Each using-declarator in a using-declaration98 introduces a set of
declarations into the declarative region in which the
using-declaration appears.
and
10 A using-declaration is a declaration and can therefore be used
repeatedly where (and only where) multiple declarations are allowed.
and (The C++ 17 Standard, 11.3.6 Default arguments)
...When a declaration of a function is introduced by way of a
using-declaration (10.3.3), any default argument information
associated with the declaration is made known as well. If the function
is redeclared thereafter in the namespace with additional default
arguments, the additional arguments are also known at any point
following the redeclaration where the using-declaration is in scope.
So this program
#include <iostream>
void f( int x, int y = 20 )
{
std::cout << "x = " << x << ", y = " << y << '\n';
}
int main()
{
using ::f;
void f( int, int );
f( 10 );
return 0;
}
as expected compiles and outputs
x = 10, y = 20
In fact it is similar to the program
#include <iostream>
void f( int x, int y )
{
std::cout << "x = " << x << ", y = " << y << '\n';
}
int main()
{
void f( int, int = 20 );
void f( int, int );
f( 10 );
return 0;
}
Now it would be logical consistent that the following program also was valid.
#include <iostream>
void f( int x, int y = 20 )
{
std::cout << "x = " << x << ", y = " << y << '\n';
}
int main()
{
using ::f;
void f( int, int );
f( 10 );
void f( int = 10, int );
f();
return 0;
}
However this program does not compile.
On the other hand, consider the following program.
#include <iostream>
namespace N
{
int a = 10;
int b = 20;
void f( int, int = b );
}
int a = 30;
int b = 40;
void N::f( int x = a, int y )
{
std::cout << "x = " << x << ", y = " << y << '\n';
}
int main()
{
using N::f;
f();
return 0;
}
It compiles successfully and its output is
x = 10, y = 20
So could be the same principles applied to functions introduced by the using declaration?
What is the reason of that such an addition of default arguments is not allowed?
You can only declare new default arguments in the same scope as the original declaration. using does not change this.
For non-template functions, default arguments can be added in later declarations of a function in the same scope.
dcl.fct.default/4
I believe
any default argument information associated with the declaration is made known as well
doesn't mean the arguments are actually imported into the scope, it's just known that they do exist and can be used.
That would mean that void f( int = 10, int ); isn't adding to void f( int x, int y = 20 ), but is instead trying to add to void f( int, int ); which would be illegal as there isn't a default argument for the second parameter in the scope that the using declaration is in.
Is there a way to check if certain variable is initialized before some point in a program?
For example, how to check if certain variable is initialized somewhere before the IfStmt node?
Methods from VarDecl class (hasInit() and getInit()) are not enough because of the following situation:
int x = 0; // hasInit() return true
int y;
...
y = 0; // initialized here, but hasInit() returns false
...
if (...) {}
If you maintain a product written by C++ code and hope to remove ugly indeterminate variables, a reasonable way to do it is defining an initializing function or lambda f, and then declare a local variable as const auto x = f(...); from the get-go.
OTOH, if you delay the value asignment on purpose, there are several methods to detect the value is assigned or not.
I just came up with following methods.
std::optional
In C++17 and over,
std::optional<T> enables us to detect whether values are assigned or not.
std::optional::has_value and std::optional::value correspond to your hasInit and getInit respectively as follows:
DEMO
#include <iostream>
#include <optional>
template<typename T>
void checkInitialization(const std::optional<T>& a)
{
if(a.has_value()){
std::cout << "Value is assigned by " << a.value() << "." << std::endl;
}
else{
std::cout << "Value is still not assigned." << std::endl;
}
}
int main(void)
{
std::optional<int> x;
checkInitialization(x); // Value is still not assigned
x = 1;
checkInitialization(x); // Value is assigned
return 0;
}
The output is as follows:
Value is still not assigned.
Value is assigned by 1.
std::unique_ptr
We can also check it using std::unique_ptr<T> which is introduced from C++11.
First we define a variable as std::unique_ptr<T> x; where (x == nullptr) is still true.
Later on, we assign a value by x = std::unique_ptr<int>(new int(1)) and then (x == nullptr) becomes false.
(In C++14 x = std::make_unique<int>(1) works and is simple.)
Thus we can again get the previous output with the following code:
DEMO
#include <iostream>
#include <memory>
template<typename T>
bool hasInit(const std::unique_ptr<T>& a)
{
return (a != nullptr);
}
template<typename T>
const T& getInit(const std::unique_ptr<T>& a)
{
return *a;
}
template<typename T>
void checkInitialization(const std::unique_ptr<T>& a)
{
if(hasInit(a)){
std::cout << "Value is assigned by " << getInit(a) << "." << std::endl;
}
else{
std::cout << "Value is still not assigned." << std::endl;
}
}
int main(void)
{
std::unique_ptr<int> x;
checkInitialization(x); // Uninitialized
x = std::unique_ptr<int>(new int(1));
//x = std::make_unique<int>(1); // C++14
checkInitialization(x); // Initialized
return 0;
}
std::pair
We can also apply std::pair<bool, T> where std::pair::first and std::pair::second correspond to your hasInit and getInit respectively.
We again get the previous output:
DEMO
#include <iostream>
#include <utility>
template<typename T>
void checkInitialization(const std::pair<bool, T>& a)
{
if(a.first){
std::cout << "Value is assigned by " << a.second << "." << std::endl;
}
else{
std::cout << "Value is still not assigned." << std::endl;
}
}
int main(void)
{
std::pair<bool, int> x{false, 0};
checkInitialization(x); // Uninitialized
x = {true, 1};
checkInitialization(x); // Initialized
return 0;
}
Firstly as mentioned in the comments:
int y = 0; // initialization
int y; y = 0; // assignment
Let's assume you want to detect assignment. One simple way could be wrap the integer you want to track in a struct and write a custom operator = (int). For example:
struct Foo
{
Foo() {std::cout << "default init" << std::endl;}
Foo& operator = (int elem)
{
cout<<"Int-Assignment operator called "<<endl;
x = elem;
is_assigned = true;
return *this;
}
int x = 0; // default initialized to 0
bool is_assigned = false; // default initialized to false
};
Now let's see what happens:
int main()
{
Foo t1;
// t1.is_assigned is false
t1 = 0;
// t1.is_assigned is true
return 0;
}
You could use something like this or a variant if needed. Here's the code running online corresponding to the above.
Is this what you wanted?
This question already has answers here:
What is the difference between prefix and postfix operators?
(13 answers)
Closed 5 years ago.
I come across this problem accidentally.
I have thought google can solve it surely, but after searching multiple keywords, I still can't find answers, which confused me a lot.
When I use prefix at tail position, codes works fine:
template<class ContinerIterator, class F>
constexpr auto fun(ContinerIterator IteratorBegin, ContinerIterator IteratorEnd, F f)
{
switch (IteratorBegin == IteratorEnd)
{
case true: return;
case false: f(*IteratorBegin);
}
return fun(++IteratorBegin, IteratorEnd, f);
}
int main()
{
std::vector<int> a = { 1, 2, 3, 4 };
fun(std::begin(a), std::end(a), [](auto &a)->auto{a *= 2; });
for (auto v : a)
{
std::cout << v << std::endl;
}
return 0;
}
1
2
3
4
Press any key to continue . . .
Howerer, if I use postfix, IteratorBegin nerve arrives iteratorEnd and goes far and far away, so segmentfault.
template<class ContinerIterator, class F>
constexpr auto fun(ContinerIterator IteratorBegin, ContinerIterator IteratorEnd, F f)
{
switch (IteratorBegin == IteratorEnd)
{
case true: return;
case false: f(*IteratorBegin);
}
return fun(IteratorBegin++, IteratorEnd, f);
}
void test()
{
}
int main()
{
std::vector<int> a = { 1, 2, 3, 4 };
fun(std::begin(a), std::end(a), [](auto &a)->auto{a *= 2; });
for (auto v : a)
{
std::cout << v << std::endl;
}
return 0;
}
I have tried on MSVC, G++, Clang, all fails.
Here is gcc's error list:
Segmentation fault (core dumped)
Here is Clang's:
Error occurred (timeout). Try again later.
This statement
return fun(IteratorBegin++, IteratorEnd, f);
with some exceptions can be considered like
fun(IteratorBegin, IteratorEnd, f);
++IteratorBegin;
return;
So the function is always called with the same value of IteratorBegin.
From the C++ Standard (5.2.6 Increment and decrement)
1 The value of a postfix ++ expression is the value of its operand. [
Note: the value obtained is a copy of the original value —end note
]...
Consider the following simple program
#include <iostream>
void f(int x)
{
std::cout << "Inside f( x ): x = " << x << std::endl;
}
int main()
{
int x = 0;
std::cout << "Before f( x ): x = " << x << std::endl;
f(x++);
std::cout << "After f( x ): x = " << x << std::endl;
return 0;
}
Its output is
Before f( x ): x = 0
Inside f( x ): x = 0
After f( x ): x = 1
Also it will be useful to consider the following simple program
#include <iostream>
int x = 0;
void f(int x)
{
std::cout << "Local (parameter) x = " << x << std::endl;
std::cout << "Global variable ::x = " << ::x << std::endl;
}
int main()
{
f(x++);
return 0;
}
Its output is
Local (parameter) x = 0
Global variable ::x = 1
The prefix case:
return fun(++IteratorBegin, IteratorEnd, f);
says, first increment IteratorBegin by one, and then call the function fun. After that, return.
On the other hand, the postfix case:
return fun(IteratorBegin++, IteratorEnd, f);
says, first call fun(), then increment the iterator, and then return.
This means that fun() is always being called with the non-incremented iterator.
When you use postfix increment in the tail call, the recursive call does not get the incremented value of the iterator. It gets the value of the iterator before the increment is applied. Hence, the recursion is infinite. That causes stack overflow.
#include <iostream>
typedef std::function<bool(int)> set;
using namespace std;
set singletonSet(int a) {
return [&] (int x) { return (a == x); };
}
bool contains(set s, int test) {
return s(test);
}
int main() {
auto first = singletonSet(5);
auto r1 = contains(first, 10);
auto r2 = contains(first, 5);
cout << r1 << " " << r2 << endl;
return 0;
}
I expect this to print 0 1 but result is 1 1
Beginner c++ labmda programmer here so sorry in advance if this is a basic error.
Don't capture a by reference, capture it by value. As-is, you're storing a dangling reference inside the lambda, and using it later leads to UB.
set singletonSet(int a) {
return [=] (int x) { return (a == x); };
// ^
}