can boost::bind be used with references without copying? - c++

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));

Related

std::visit with passing pointer fails to compile under clang 13

The following code compiles properly under x64 msvc x19.30 and gcc 11 but fails to compile under clang 13.0.1:
"error: cannot pass object of non-trivial type 'std::shared_ptr<std::pair<int, std::variant<Struct1, Struct2, UnsupportedStruct>>>' through variadic function;"
Does anyone know what the problem is?
The following code produces different outputs depending on passing object:
#include <iostream>
#include <variant>
#include <memory>
struct Struct1{};
struct Struct2{};
struct UnsupportedStruct{};
using VarTypeData = std::variant<Struct1, Struct2, UnsupportedStruct>;
using VarType = std::pair<int, VarTypeData>;
namespace
{
void print(Struct1&, std::shared_ptr<VarType> v) {std::cout << v->first << ": Struct1\n";}
void print(Struct2&, std::shared_ptr<VarType> v) {std::cout << v->first << ": Struct2\n";}
void print(...) {std::cout << "no implementation";}
}
int main()
{
VarType data1 = std::make_pair(100, UnsupportedStruct{});
auto pointerData = std::make_shared<VarType>(data1);
std::visit([&pointerData](auto& c) {print(c, pointerData);}, pointerData->second);
std::cout << std::endl;
pointerData->second = Struct1{};
std::visit([&pointerData](auto& c) {print(c, pointerData);}, pointerData->second);
}
This code works fine for clang after dereferencing:
#include <iostream>
#include <variant>
#include <memory>
struct Struct1{};
struct Struct2{};
struct UnsupportedStruct{};
using VarTypeData = std::variant<Struct1, Struct2, UnsupportedStruct>;
using VarType = std::pair<int, VarTypeData>;
namespace
{
void print(const Struct1&, const VarType& v) {std::cout << v.first << ": Struct1\n";}
void print(const Struct2&, const VarType& v) {std::cout << v.first << ": Struct2\n";}
void print(...) {std::cout << "no implementation";}
}
int main()
{
VarType data1 = std::make_pair(100, UnsupportedStruct{});
auto pointerData = std::make_shared<VarType>(data1);
std::visit([&pointerData](auto& c) {print(c, *pointerData);}, pointerData->second);
std::cout << std::endl;
pointerData->second = Struct1{};
std::visit([&pointerData](auto& c) {print(c, *pointerData);}, pointerData->second);
}
thanks to #康桓瑋 for the answer.
this code does not work for clang, because of
void print(...) {std::cout << "no implementation";}
answer: void print(...) is a C function, where variadic actually means the
's parameter. It accepts only trivial types, which
std::shared_ptr is not. So the behavior is undefined or only
conditionally supported
So, the following changes fix the problem:
template<class... Args>
void print(Args&&...) {std::cout << "no implementation";}

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.

using std::apply on std::bind

The following fails to compile with gcc 8.2.0 [stacktrace]
#include <iostream>
#include <tuple>
#include <functional>
void print(int a, int b, int c) {
std::cout << a << ", " << b << ", " << c << std::endl;
}
int main() {
auto b = std::bind(print, 1);
auto t = std::make_tuple(2, 3);
std::apply(b, t);
}
I personally fail to see why, it would seem to be common sense for it to work (in a proper functional language at least).
Could somebody explain the reason it doesn't work?
With std::bind you need to also provide placeholders for the unbound arguments.
auto b = std::bind(print, 1, std::placeholders::_1, std::placeholders::_2);

C++11: How is boost::make_tuple different from std::make_tuple?

http://en.cppreference.com/w/cpp/utility/tuple/make_tuple
(for convenience code is pasted)
#include <iostream>
#include <tuple>
#include <functional>
std::tuple<int, int> f() // this function returns multiple values
{
int x = 5;
return std::make_tuple(x, 7); // return {x,7}; in C++17
}
int main()
{
// heterogeneous tuple construction
int n = 1;
auto t = std::make_tuple(10, "Test", 3.14, std::ref(n), n);
n = 7;
std::cout << "The value of t is " << "("
<< std::get<0>(t) << ", " << std::get<1>(t) << ", "
<< std::get<2>(t) << ", " << std::get<3>(t) << ", "
<< std::get<4>(t) << ")\n";
// function returning multiple values
int a, b;
std::tie(a, b) = f();
std::cout << a << " " << b << "\n";
}
https://theboostcpplibraries.com/boost.tuple
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>
#include <string>
#include <iostream>
int main()
{
typedef boost::tuple<std::string, int, bool> animal;
animal a = boost::make_tuple("cat", 4, true);
a.get<0>() = "dog";
std::cout << std::boolalpha << a << '\n';
}
It would seem based on the documentation that boost::make_tuple and std::make_tuple are exactly interchangeable.
Are they really exactly interchangeable? In what circumstances are they not?
In the boost documentation it says that boost::tuple and std::tuple are the same in c++11
In the std documentation it says make_tuple returns a std::tuple.
So are there any nuances that I am missing?
There's no functional difference.
boost::tuple was created almost two decades ago, and std::tuple was introduced to the core Standard Library in C++11, in 2011, only 6 years ago.
They're not "interchangable", for a given definition of the term "interchangable". You can't assign a std::tuple<> to a boost::tuple<> or vice-versa, because even if their implementation is the same, they still represent distinct objects.
However, because they are essentially the same, you can do a find→replace for boost::tuple→std::tuple and more-or-less arrive with identically behaving and performing code, and because dependency on the boost libraries is not something every programmer can have, it's almost universally recommended that any project which has access to >=C++11 prefer std::tuple in all cases.
EDIT:
As pointed out by #Nir, there are a few syntactical differences between boost::tuple and std::tuple, notably involving the get<>() syntax, which is also a member function of boost::tuple and only a free function for std::tuple.

passing boost::optional lvalue as a reference to a function

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