passing boost::optional lvalue as a reference to a function - c++

Can you somehow pass boost::optional lvalue as a reference into a function which changes the value? Something like this (http://coliru.stacked-crooked.com/a/f77d3b095af3d66b):
#include <iostream>
#include <boost/optional.hpp>
void foo(int& x)
{
x = 3;
}
int main() {
boost::optional<int> y;
foo(*y);
std::cout << *y << std::endl;
}
which doesn't work, unsurprisingly.
The function needs to use standard type as the output argument tho (e.g. int& x). I hope I am explaining this correctly. I am asking about general possibility of my intention.

Yes. you just have to initialize the optional like your compilation error suggests:
boost::optional::reference_type boost::optional::get() [with T = int; boost::optional::reference_type = int&]: Assertion `this->is_initialized()' failed.
This works & prints 3:
#include <iostream>
#include <boost/optional.hpp>
void foo(int& x)
{
x = 3;
}
int main() {
boost::optional<int> y = 2;
foo(*y);
std::cout << *y << std::endl;
}
An important remark noted by the op, is that even if the initialization value is not known in compile time, boost will anyway assert the optional's state (on operator* or on get()), which means that if the optional is not set (boost::none) the application will crash.
So one can either initialize with a valid-value-containing optional (non boost::none), or pass optional<int>&.

You want to be very careful here. If you swap boost::optional for std::optional then std::optional does not protect you with the compiler. See that with std::optional i have not initialized. There is no compiler error. I am allowed to write to the optional but the optional is still not considered initialized ie (bool)y == false
#include <iostream>
#include <boost/optional.hpp>
#include <boost/optional/optional_io.hpp>
#include <optional>
void foo(int& x)
{
x = 3;
}
int main() {
{
boost::optional<int> y = 2;
foo(*y);
std::cout << *y << " " << !!y << std::endl;
}
{
std::optional<int> y;
foo(*y);
std::cout << *y << " " << !!y << std::endl;
}
}
output is
3 1
3 0
http://coliru.stacked-crooked.com/a/a169e7c43052a206

Related

Why is this C++ code which uses decltype and remove_reference with the goal of getting the value type of a pointer working unexpectedly

When I run the snippet below, it prints out:
int&
int __cdecl(void)
I was expecting the second line to just be int
Why is this happening? What could I do to fix it if it were inside a templated function that takes pointers or iterators so I couldn't use std::remove_pointer.
#include <type_traits>
#include <iostream>
int main()
{
int r = 4;
int* rp = &r;
using return_type = decltype(*rp);
using no_ref_type = std::remove_reference<return_type>::type();
std::cout << typeid(return_type).name() << '&' << std::endl;
std::cout << typeid(no_ref_type).name();
}

New type of auto-generated constructor in C++20

The code below doesn't compile on GCC 11 with -std=c++17, but does with -std=c++20:
#include <iostream>
#include <string>
struct Foo {
std::string s;
int i;
};
int main()
{
Foo foo("hello", 42);
std::cout << foo.s << ' ' << foo.i << '\n';
}
What's the feature in C++20 that enables this? What kind of constructor is generated by the compiler?
The C++20 feature being used here is the initialization of aggregates from parenthesis (P0960R3):
This paper proposes allowing initializing aggregates from a parenthesized list of values; that is, Aggr(val1, val2) would mean the same thing as Aggr{val1, val2}, except that narrowing conversions are allowed.
Here is an example from the above link:
struct A {
int a;
int&& r;
};
int f();
int n = 10;
A a1{1, f()}; // OK, lifetime is extended
A a2(1, f()); // well-formed, but dangling reference
A a3{1.0, 1}; // error: narrowing conversion
A a4(1.0, 1); // well-formed, but dangling reference
A a5(1.0, std::move(n)); // OK
So, for your code to work with C++17, just replace the parenthesis with braces.
#include <iostream>
#include <string>
struct Foo {
std::string s;
int i;
};
int main()
{
Foo foo{"hello", 42};
std::cout << foo.s << ' ' << foo.i << '\n';
}

Expand variadic arguments in initializer list fails

I try to create a simple program in which I want to create vector of future arguments.
I created a wrapper function which is used to submit lambda functions and stores internally in a vector the future objects
I use an intermediate step in which I create an initiliazer_list using variadic arguments . But fails to compile. I try to use to call a function in order to push the elements in the vector and fails to compile as well
Below is the code
#include <iostream>
#include <thread>
#include <future>
#include <functional>
#include <cstdlib>
#include <chrono>
#include <initializer_list>
using namespace std;
using FunctPtr = function<int(int, int) >;
using FutureInt = future<int>;
using AsyncVector = vector<FutureInt>;
AsyncVector asyncVec;
template<typename... TemplatePtr>
void submit(TemplatePtr... pFunc)
{
auto initList {pFunc... };
for (auto & element : initList)
{
asyncVec.emplace_back(async(launch::async, element,4,5));
}
}
int main()
{
int a;
int b;
auto addPtr = [](int x, int y)->int
{
std::cout << "add :" << x + y << std::endl;
return x + y;
};
auto multPtr = [](int x, int y)->int
{
std::cout << "mult :" << x * y << std::endl;
return x * y;
};
// submit(add,4,5);
submit(addPtr, multPtr);
for (auto & v : asyncVec)
{
std::cout << "Wait for " << v.get() << std::endl;
}
}
Yes, they are of different types so cannot be in the same init-list easily.
Your best options should probably be:
Either push them all into asyncVec in the same fold-expression.
template<typename... TemplatePtr>
void submit(TemplatePtr... pFunc)
{
(asyncVec.emplace_back(async(launch::async, std::move(pFunc), 4, 5)), ...);
}
Or, if they all are of the same signature, type-erase them, like keeping them in an array of std::function.
template<typename... TemplatePtr>
void submit(TemplatePtr... pFunc)
{
for (auto &&element: {std::function<int(int, int)>(std::move(pFunc))...})
{
asyncVec.emplace_back(async(launch::async, std::move(element), 4, 5));
}
}
(I have specified function signature explicitly though compiler should be able to deduce it.)
Or, if all closures are captureless and of the same signature, simply cast them to the same type when calling submit:
using SameType = int (*)(int, int);
submit(static_cast<SameType>(addPtr), static_cast<SameType>(mulPtr));
This way your original submit should work as is.

I compiled this seemingly incorrect code, but I don’t understand why

I am learning C++ on a linux machine. I just tried “int i();” to declare a function but I forgot to define it. But to my surprise, this code can be compiled and output 1. I feel very confused. I tried “int I{};”, it still compiled with no errors. Please help to explain. Thanks in advance.
//test1.cpp
#include <iostream>
int main(void)
{
int i{};
std::cout << i << std::endl;
return 0;
}
g++ test1.cpp
./a.out
Output is: 0
//test2.cpp
#include <iostream>
int main(void)
{
int i();
std::cout << i << std::endl;
return 0;
}
g++ test2.cpp
./a.out
Output is : 1
In your first example, you define a variable named i, and value-initialise it, which for int means zero-initialisation.
int i{}; // defines i, initialised to zero
In your second example, you declare a function named i, which takes no parameters, and return int:
int i(); // declares a function
When you print this:
std::cout << i << std::endl;
i first get converted to bool (i decays to a function non-nullptr pointer, then it becomes true), and then printed as an integer, that's why you get 1. The compiler can make this conversion without the definition of i (as the result is always true), that's why you got no linker error.
If your intent was to call this function, and print the result, you'll need to use i():
std::cout << i() << std::endl;
This, of course, needs i's definition.
In your code:
//test1.cpp
#include <iostream>
int main(void)
{
int i{};
std::cout << i << std::endl;
return 0;
}
You are not actually declaring a function without defining it. The line of code int i{}; within the main() function here is a variable of type int named i and you are using a brace initializer list to initialize the variable i with out any values and in most cases could be 0 but can vary by compiler.
//test2.cpp
#include <iostream>
int main(void)
{
int i();
std::cout << i << std::endl;
return 0;
}
In this situation it is basically the same thing. You are within main() and by the rules of the language "you can not declare-define a function within a function", so this results in a declaration - definition of a variable. The only difference here is you are not using a brace initializer list here you are using it's ctor constructor called value initialization. Again you are not passing any values to it and in your case it's assigning an arbitrary value of 1.
Now if your code looked like this:
#include <iostream>
int i();
int main() {
std::cout << i() << '\n';
return 0;
}
This would fail to compile because the function i is declared but not defined. However if you did this:
#include <iostream>
// The text in quotes is not meant to be a string literal. It
// is the message of the text that represents any integer X.
int i() { return /*"some int value"*/ 1; }
int main() {
std::cout << i() << '\n';
return 0;
}
This would compile and run perfectly fine because the function i is both declared and defined.

can boost::bind be used with references without copying?

Following code shows that the parameter, passed by reference, is copied when using boost::bind. Is there a way to prevent the copying without resorting to pointers (which I currently use as workaround)? (tested with gcc 4.4.3)
#include <iostream>
#include <boost/function.hpp>
#include <boost/bind.hpp>
void function1(int& x)
{
std::cout << "function1 &x: " << &x << std::endl;
}
int main()
{
int y = 0;
std::cout << "main &y: " << &y << std::endl;
boost::function<void()> f = boost::bind(function1, y);
f();
}
You should use boost::ref for passing references to boost bind.
boost::function<void()> f = boost::bind(function1, boost::ref(y));