Consider the following uncomplicated code:
#include <thread>
#include <utility>
#include <vector>
#include <atomic>
#include <queue>
#include <iostream>
#include <functional>
using namespace std;
template<class It, class Fun>
void parallel_for(size_t num_threads, It first, It end, const Fun& fun) {
std::queue<std::thread> ts;
for (It it = first; it != end; ++it) {
if (std::distance(first, it) % num_threads == 0) {
fun(*it);
} else {
if (ts.size() == num_threads-1) {
ts.front().join();
ts.pop();
}
ts.push(std::thread(fun, std::ref(*it)));
}
}
while (not ts.empty()) {
ts.front().join();
ts.pop();
}
}
int main() {
std::atomic_int counter = 1;
auto lam = [&counter](auto& vl) {
vl = std::pair(counter++, -1);
};
// The following usage of std::ref works okay:
pair<int, int> x;
auto blam = bind(lam, ref(x));
blam();
// Nevertheless, the next line fails:
// lam(ref(x));
// As well as the next two ones:
// vector<pair<int, int>> v = {{4, 2}};
// parallel_for(thread::hardware_concurrency(), begin(v), end(v), lam);
return 0;
}
GCC's error on the last two lines, in particular, is
In file included from ./src/csc_cpp/passing_lambdas.cpp:1:
/usr/include/c++/10/thread: In instantiation of ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = const main()::<lambda(auto:1&)>&; _Args = {std::reference_wrapper<std::pair<int, int> >}; <template-parameter-1-3> = void]’:
./src/csc_cpp/passing_lambdas.cpp:22:26: required from ‘void parallel_for(size_t, It, It, const Fun&) [with It = __gnu_cxx::__normal_iterator<std::pair<int, int>*, std::vector<std::pair<int, int> > >; Fun = main()::<lambda(auto:1&)>; size_t = long unsigned int]’
./src/csc_cpp/passing_lambdas.cpp:47:71: required from here
/usr/include/c++/10/thread:136:44: error: static assertion failed: std::thread arguments must be invocable after conversion to rvalues
136 | typename decay<_Args>::type...>::value,
| ^~~~~
I am sure this is a trivial matter, but I am anyway struggling to understand this. I think I have been following the available examples on std::thread::thread()'s intended use quite closely, but this does not compile. What am I doing wrong?
First, let me clarify, because I'm not sure if it's obvious: the trick behind std::ref is that it returns an object of type std::reference_wrapper<T>, so you can use the result as object, but the object is implicitly convertible to T&, so it can be substituted where T& is needed.
lam(ref(x)); fails because you use auto in lam. Compiler doesn't know that you want vl to be std::pair<int, int>&, it deduces from what it gets. std::ref returns a temporary of std::reference_wrapper<std::pair<int, int>>, which cannot be bound to non-const reference. Use explicit type in lambda and it compiles:
auto lam = [&counter](std::pair<int, int>& vl) {
vl = std::pair(counter++, -1);
};
lam(std::ref(x));
Alternatively, you can explicitly convert to std::pair<int, int>& using get() or static_cast
auto lam = [&counter](auto& vl) {
vl = std::pair(counter++, -1);
};
lam(std::ref(x).get());
lam(static_cast<std::pair<int, int>&>(std::ref(x)));
The second part with parallel_for has exactly the same issue, you pass rvalue of std::reference_wrapper to lam.
About
lam(ref(x));
x is an lvalue while the ref(x) is a temporary reference_wrapper. You can not grab a temporary with an lvalue reference in your lam through auto&.
for that line, you can simply use
lam(x);
Related
I am new to move semantics and want to understand what's happening in this piece of code:
vector<int> create_vector() {
return {0, 1, 2};
}
for (int &x : create_vector()) {
/* ... */
}
If I understand correctly, the function call create_vector() returns an rvalue. Therefore, the elements inside it should be rvalues as well (i.e. 0, 1, 2 are rvalues). However, in the range for loop, we are binding these rvalues to a non-const lvalue reference int &x, which shouldn't be allowed? I thought non-const lvalue references can only bind to lvalues, not rvalues.
What's happening here? Why is this allowed?
You're returning the Container with rvalue, but the individual elements are being returned after calling ::begin() on the vector and then calling the operator*() on the returned iterator which returns a reference as you can see here:
// Forward iterator requirements
_GLIBCXX20_CONSTEXPR
reference
operator*() const _GLIBCXX_NOEXCEPT
{ return *_M_current; }
If you write the for loop in the cppinsights.io then you'll see that the for loop is calling .begin and then it's calling the operator*():
#include <vector>
using namespace std;
int foo() {
int res;
for (auto& val : vector<int>{}) {
res += val;
}
return res;
}
Here's the link that produces this from the above example:
#include <vector>
using namespace std;
int foo()
{
int res;
{
std::vector<int, std::allocator<int> > && __range1 = std::vector<int, std::allocator<int> >{};
__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > > __begin1 = __range1.begin();
__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > > __end1 = __range1.end();
for(; !__gnu_cxx::operator==(__begin1, __end1); __begin1.operator++()) {
int & val = __begin1.operator*();
res = res + val;
}
}
return res;
}
Here's the vector::begin on cppreference; and here's a link to itrator_traits which can be used to get the reference/pointer type of vector's iterator like this:
using your_vector = std::vector<int>;
using vector_iterator = typename your_vector::iterator;
using traits = std::iterator_traits<vector_iterator>;
using reference_type = typename traits::reference;
using pointer_type = typename traits::pointer;
There are easier ways to get these types but it's the universal way for standard containers.
Consider the following example
#include <iostream>
#include <any>
#include <vector>
#include <map>
#include <typeinfo>
typedef enum TYPE{
INT8=0,
INT16=1,
INT32=2
} TYPE;
int main()
{
std::map<TYPE, std::any> myMap;
myMap[TYPE::INT8] = (int8_t)0;
myMap[TYPE::INT16] = (int16_t)0;
myMap[TYPE::INT32] = (int32_t)0;
std::vector<decltype(myMap[TYPE::INT8])> vec;
}
I have a map in this example, going from some enum to std::any. I actually need a flexible data structure that can map from a specific type (enum TYPE in this case), to multiple data types (different types of int), hence the use of std::any.
Going ahead, I would like to ascertain the type of value given for the key and construct a vector with it. I tried the above code, and it runs into a compilation error because decltype will return std::any(correctly so).
I would want to extract the "true type" from the std::any and create that type of vector. How would I achieve that.
A small snippet of the compilation error is as follows -
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/new_allocator.h:63:26: error: forming pointer to reference type 'std::any&'
63 | typedef _Tp* pointer;
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/new_allocator.h:112:7: error: forming pointer to reference type 'std::any&'
112 | allocate(size_type __n, const void* = static_cast<const void*>(0))
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_vector.h:1293:7: error: 'void std::vector<_Tp, _Alloc>::push_back(value_type&&) [with _Tp = std::any&; _Alloc = std::allocator<std::any&>; value_type = std::any&]' cannot be overloaded with 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::any&; _Alloc = std::allocator<std::any&>; value_type = std::any&]'
1293 | push_back(value_type&& __x)
TIA
As suggested in the comments by #Ted Lyngmo, I think std::variant serves you better. Especially with C++-20's templated lambdas, the std::visit function can work wonders with these to get around the awkwardness of dealing with type enums and the like.
Note that you can not get around the runtime type detection. In any case, here is an example of how it can work.
#include <cstdint>
#include <iostream>
#include <variant>
#include <vector>
using VariantScalar = std::variant<
std::int8_t, std::int16_t, std::int32_t>;
using VariantVector = std::variant<
std::vector<std::int8_t>,
std::vector<std::int16_t>,
std::vector<std::int32_t>>;
VariantVector fill_vector(VariantScalar scalar, std::size_t n)
{
auto make_vector = [n]<class IntType>(IntType v) -> VariantVector {
return std::vector<IntType>(n, v);
};
return std::visit(make_vector, scalar);
}
void print_vector(const VariantVector& vec)
{
std::visit([]<class T>(const std::vector<T>& vec) {
for(const T& s: vec)
std::cout << s << ' ';
std::cout << '\n';
}, vec);
}
int main()
{
VariantScalar s(std::int8_t(1));
VariantVector vec = fill_vector(s, 5);
print_vector(vec);
}
Assuming you have the following enum definition:
enum class TYPE{
INT8=0,
INT16=1,
INT32=2
};
Then you can define a helper:
template <TYPE>
struct my_type {}; // Base case
template <>
struct my_type<TYPE::INT8> {
using type = int8_t;
};
template <>
struct my_type<TYPE::INT16> {
using type = int16_t;
};
template <>
struct my_type<TYPE::INT32> {
using type = int32_t;
};
template <TYPE t>
using my_type = typename my_type<t>::type;
That you can use for your vector
std::vector<my_type<TYPE::INT8>> vec;
I'm trying to use adjacent_difference with two different iterator types. The functor I have created takes the type used by the InputIterator as parameters and returns the type used by the OutputIterator. I don't understand why the code I included doesn't compile:
In file included from /usr/include/c++/4.9/numeric:62:0,
from 4: /usr/include/c++/4.9/bits/stl_numeric.h: In instantiation of '_OutputIterator
std::adjacent_difference(_InputIterator, _InputIterator,
_OutputIterator, _BinaryOperation) [with _InputIterator = __gnu_cxx::__normal_iterator >; _OutputIterator = __gnu_cxx::__normal_iterator >; _BinaryOperation = {anonymous}::CheckOp]':
48:85: required from here
/usr/include/c++/4.9/bits/stl_numeric.h:374:17: error: cannot convert
'_ValueType {aka Test}' to 'float' in assignment
*__result = __value;
// Example program
#include <iostream>
#include <string>
#include <numeric>
#include <vector>
struct Test
{
float first;
float second;
};
namespace{
class CheckOp {
public:
float operator()(Test x, Test y) const
{
float a = x.first - y.first;
float b = x.second - y.second;
return a + b;
}
};
}
int main()
{
std::vector<Test> testVec;
Test test1;
test1.first = 5.5F;
test1.second = 6.5F;
testVec.push_back(test1);
Test test2;
test2.first = 2.5F;
test2.second = 8.5F;
testVec.push_back(test2);
Test test3;
test3.first = 9.4F;
test3.second = 7.8F;
testVec.push_back(test3);
CheckOp checkOP;
std::vector<float> resultVec(testVec.size());
std::adjacent_difference(testVec.begin(), testVec.end(), resultVec.begin(), checkOP);
}
Note the description of adjacent_difference (from cppreference):
First, creates an accumulator acc whose type is InputIt's value type, initializes it with *first, and assigns the result to *d_first.
This implies that the input and output sequences must have the same, or at least a compatible, type.
I am trying to achieve something like this but getting boost bind related errors
#include <map>
#include "boost/assign.hpp"
#include <boost/foreach.hpp>
#include <string>
#include <boost/function.hpp>
#include <boost/bind.hpp>
struct myStruct_t
{
int getInt () {return 1;};
};
int foo( myStruct_t* m, std::string str)
{
if(str == "A")
{
return m->getInt();
}
else if (str == "B")
{
return 2;
}
else
{
return 3;
}
}
typedef std::map<std::string, boost::function<int(myStruct_t*, std::string)> > Map_t;
Map_t myMap = boost::assign::map_list_of ("Jake", boost::bind((&foo, _1), "A")
("Ken", boost::bind((&foo, _1), "B")
("Pete", boost::bind((&foo, _1), "C");
int main ()
{
std::vector<std::string> myVal;
myVal.push_back("Jake");
myVal.push_back("Ken");
myVal.push_back("Pete");
myStruct_t myStruct;
BOOST_FOREACH( const std::string& aStr, myVal)
{
Map_t::const_iterator iter = myMap.find(aStr);
if(iter != myMap.end())
{
int myInt = (iter->second)(myStruct);
}
}
return 0;
}
The errors I am getting are
In file included from /usr/local/boost-1.60.0/include/boost/bind.hpp:22:0,
from prog.cc:6:
/usr/local/boost-1.60.0/include/boost/bind/bind.hpp: In instantiation of 'boost::_bi::result_traits<boost::_bi::unspecified, boost::arg<1> >':
/usr/local/boost-1.60.0/include/boost/bind/bind.hpp:1212:48: instantiated from 'boost::_bi::bind_t<boost::_bi::unspecified, boost::arg<1>, boost::_bi::list1<boost::_bi::value<const char*> > >'
prog.cc:32:81: instantiated from here
/usr/local/boost-1.60.0/include/boost/bind/bind.hpp:75:37: error: no type named 'result_type' in 'struct boost::arg<1>'
prog.cc:34:82: error: expected ')' before ';' token
prog.cc: In function 'int main()':
prog.cc:50:48: error: no match for call to '(const boost::function<int(myStruct_t*, std::basic_string<char>)>) (myStruct_t&)'
/usr/local/boost-1.60.0/include/boost/function/function_template.hpp:765:17: note: candidate is: result_type boost::function2<R, T1, T2>::operator()(T0, T1) const [with R = int, T0 = myStruct_t*, T1 = std::basic_string<char>, result_type = int]
It seems I am puzzled the way boost::bind is used. Can someone please help me doing it correctly? Many Thanks.
The function signature expected at the call site is int(myStruct*)
because of this line (I added the & to remove a logic error):
int myInt = (iter->second)(&myStruct);
in which case the declaration of the map should be:
typedef std::map<std::string, boost::function<int(myStruct_t*)> > Map_t;
Map_t myMap = boost::assign::map_list_of
("Jake", boost::bind(&foo, boost::placeholders::_1, std::string("A")))
("Ken", boost::bind(&foo, boost::placeholders::_1, std::string("B")))
("Pete", boost::bind(&foo, boost::placeholders::_1, std::string("C")));
And then you're good to go.
explanation:
boost[std]::bind returns a function object which is designed to accept only the parameters that are mentioned as placeholders in the bind expression.
This means that the function that is finally called will often have more arguments than the function object returned by bind
so in your case, foo has the following signature:
int foo( myStruct_t* m, std::string str)
i.e. takes two arguments and returns an int.
However at the point of the call to bind:
boost::bind(&foo, boost::placeholders::_1, std::string("A"))
What we're saying is "capture the function foo and the second argument (a string). Return me a function object that requires one argument (_1) and forward that argument as the first argument to foo while passing the bound string as the second argument.
so given:
auto f = boost::bind(&foo, boost::placeholders::_1, std::string("A"));
f has the signature int f(MyStruct*)
and when called with
auto i = f(&mystruct);
it is equivalent to calling:
auto i = foo(&mystruct, std::string("A"));
Consider the following code:
#include <unordered_map>
#include <tuple>
namespace Test
{
template<typename State>
struct StateTableEntry
{
State state;
};
template<typename State>
using StateRow = std::unordered_map<int,StateTableEntry<State>>;
template<typename StateRowValueType>
auto& entryBAD(StateRowValueType& row)
{ return row.second; }
template<typename StateRowValueType>
auto entryOK(StateRowValueType& row) -> decltype((row.second))
{ return row.second; }
}
template<class T,int I,class O> std::enable_if_t<I==std::tuple_size<T>::value>
for_each_index_of(O&){}
template<class Tuple, int startingIndex=0, class Operation>
std::enable_if_t<startingIndex<std::tuple_size<Tuple>::value>
for_each_index_of(const Operation& operation)
{
operation(std::integral_constant<std::size_t,startingIndex>());
for_each_index_of<Tuple,startingIndex+1>(operation);
}
int main()
{
for_each_index_of<std::tuple<int>>([](const auto&)
{
Test::StateRow<long> stateRow;
for(auto& rowElement : stateRow)
{
auto& state(entryBAD(rowElement).state);
state=1;
}
});
}
If I try to compile it as is, gcc tells me
test.cpp: In instantiation of ‘main()::<lambda(const auto:1&)> [with auto:1 = std::integral_constant<long unsigned int, 0ul>]’:
test.cpp:29:14: required from ‘std::enable_if_t<(startingIndex < std::tuple_size<_Tp>::value)> for_each_index_of(const Operation&) [with Tuple = std::tuple<int>; int startingIndex = 0; Operation = main()::<lambda(const auto:1&)>; std::enable_if_t<(startingIndex < std::tuple_size<_Tp>::value)> = void]’
test.cpp:43:6: required from here
test.cpp:40:44: error: use of ‘template<class StateRowValueType> auto& Test::entryBAD(StateRowValueType&)’ before deduction of ‘auto’
auto& state(entryBAD(rowElement).state);
^
test.cpp:40:44: error: use of ‘auto& Test::entryBAD(StateRowValueType&) [with StateRowValueType = std::pair<const int, Test::StateTableEntry<long int> >]’ before deduction of ‘auto’
test.cpp:24:1: error: ‘std::enable_if_t<(I == std::tuple_size<_Tp>::value)> for_each_index_of(O&) [with T = std::tuple<int>; int I = 1; O = const main()::<lambda(const auto:1&)>; std::enable_if_t<(I == std::tuple_size<_Tp>::value)> = void]’, declared using local type ‘const main()::<lambda(const auto:1&)>’, is used but never defined [-fpermissive]
for_each_index_of(O&){}
^
But if I move the conde of lambda out of the lambda or replace call of entryBAD with entryOK, for some reason compilation succeeds. Same success if I move definition of entryBAD out of namespace Test.
Also, clang++ 3.6 compiles in all cases without complaints.
Is gcc right or is it a bug in it? If gcc is right, then what's wrong with the code?