How can I make a thread execute std::sort() directly, without creating an intermediate function?
Something like:
std::thread t1(std::sort, data.begin(), data.end());
My (playground!) idea is letting each thread sort half of the vector and then merge it:
#include <vector>
#include <thread>
#include <iostream>
#include <algorithm>
// Type your code here, or load an example.
void myfunc(std::vector<int>& data) {
std::sort(data.begin(), data.begin() + data.size() / 2);
return;
}
int main()
{
std::vector<int> data = { 1, 8, 123, 10, -3, 15, 2, 7 };
std::thread t1(myfunc, std::ref(data)); // works
//std::thread t1(std::sort, data.begin(), data.begin() + data.size() / 2); // doesn't
std::sort(data.begin() + data.size() / 2, data.end());
t1.join();
std::inplace_merge(data.begin(), data.begin() + data.size() / 2, data.end());
for (auto x : data)
std::cout << x << "\n";
}
Compiler error, when using the commented line instead of the one above (I used an online code editor):
error: no matching function for call to 'std::thread::thread(<unresolved overloaded function type>, std::vector<int>::iterator, __gnu_cxx::__normal_iterator<int*, std::vector<int> >)'
16 | d t1(std::sort, data.begin(), data.begin() + data.size() / 2); // doesn't
| ^
In file included from /usr/include/c++/11/thread:43,
from /tmp/bBJEjs0nrj.cpp:2:
/usr/include/c++/11/bits/std_thread.h:127:7: note: candidate: 'template<class _Callable, class ... _Args, class> std::thread::thread(_Callable&&, _Args&& ...)'
127 | thread(_Callable&& __f, _Args&&... __args)
| ^~~~~~
/usr/include/c++/11/bits/std_thread.h:127:7: note: template argument deduction/substitution failed:
/tmp/bBJEjs0nrj.cpp:16:75: note: couldn't deduce template parameter '_Callable'
16 | d t1(std::sort, data.begin(), data.begin() + data.size() / 2); // doesn't
| ^
In file included from /usr/include/c++/11/thread:43,
from /tmp/bBJEjs0nrj.cpp:2:
/usr/include/c++/11/bits/std_thread.h:157:5: note: candidate: 'std::thread::thread(std::thread&&)'
157 | thread(thread&& __t) noexcept
| ^~~~~~
/usr/include/c++/11/bits/std_thread.h:157:5: note: candidate expects 1 argument, 3 provided
/usr/include/c++/11/bits/std_thread.h:121:5: note: candidate: 'std::thread::thread()'
121 | thread() noexcept = default;
| ^~~~~~
/usr/include/c++/11/bits/std_thread.h:121:5: note: candidate expects 0 arguments, 3 provided
Desired output:
-3,1,27,8,10,15,123
The most direct translation of the original code uses a template instantiation:
std::thread t1(std::sort<std::vector<int>::iterator>,
data.begin(), data.end());
std::sort() is a function template, and as such cannot be passed as-is to a function that expects a concrete functor (a type that behaves like a function). You need to either cast std::sort to the correct function pointer type, or else wrap it in some way that lets the compiler figure out which version of std::sort() you are trying to call.
The easiest way to deal with that is to use a lambda expression to wrap the call to std::sort() so that the compiler can do the template deduction for you. That can look like this:
std::thread t1([&](){ std::sort(data.begin() + data.size() / 2, data.end()); });
You can use a lambda:
std::thread t1([&data](){std::sort(data.begin() + data.size() / 2, data.end());});
Related
I'm trying to make perfect forwarding work with initializer lists. For the sake of the example, I'd like to have a variadic function that calls into another function, and still enjoy automatic conversion of initializer lists of the latter:
#include <iostream>
#include <vector>
void hello(std::string const& text, std::vector<int> const& test)
{
std::cout << "hello " << text << " " << test.size() << std::endl;
}
template<class ... Args>
void f(Args&& ... args)
{
return hello(std::forward<Args>(args)...);
}
int main()
{
hello("world", {1,2,3}); // WORKS
f("world", std::vector<int>({1,2,3})); // WORKS
f("world", {1,2,3}); // COMPILER ERROR
}
The error is
example.cpp: In function ‘int main()’:
example.cpp:21:21: error: too many arguments to function ‘void f(Args&& ...) [with Args = {}]’
21 | f("world", {1,2,3});
| ^
example.cpp:12:6: note: declared here
12 | void f(Args&& ... args)
| ^
example.cpp: In instantiation of ‘void f(Args&& ...) [with Args = {}]’:
example.cpp:21:21: required from here
example.cpp:14:15: error: too few arguments to function ‘void hello(const string&, const std::vector<int>&)’
14 | return hello(std::forward<Args>(args)...);
| ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
example.cpp:6:6: note: declared here
6 | void hello(std::string const& text, std::vector<int> const& test)
| ^~~~~
Am I making any obvious mistake here?
The compiler is not able to recognize the type you are sending in the third case.
If you use
f("world", std::initializer_list<int>{1,2,3});
everything works.
This post has some detailed explanation and quotes the relevant part of the standard. It is for a slightly different case but the explanation still applies.
The problem is that the {1, 2, 3} argument to your second call to the templated f function is not sufficiently 'specific' for the compiler to unambiguously deduce its type in template substitution.
Explicitly defining that argument's type will resolve the issue:
f("world", std::initializer_list<int>{ 1, 2, 3 });
A very similar case is given (as an example of an error) on this cppreference page.
This code works and generates the correct output (23, as 2 and 3 are the sizes of the two std::vector<int>s in array_of_vectors:
#include <array>
#include <boost/range/adaptor/transformed.hpp>
#include <iostream>
#include <vector>
using boost::adaptors::transformed;
constexpr auto get_size = [](auto const& snip){ return snip.size(); };
int main() {
std::array<std::vector<int>,2> array_of_vectors = {
{std::vector<int>{1,1}, std::vector<int>{1,1,1}}
};
auto array_of_sizes = array_of_vectors | transformed(get_size);
for (auto i : array_of_sizes) {
std::cout << i;
}
}
On the other hand, if I try to enforce that array_of_sizes is indeed a std::array<std::size_t, 2u> via boost::copy_range by changing this
auto array_of_sizes = array_of_vectors | transformed(get_size);
to this
auto array_of_sizes = boost::copy_range<std::array<std::size_t, 2u>>(
array_of_vectors | transformed(get_size)
);
I get the following error,
$ g++ -std=c++17 deleteme.cpp && ./a.out
In file included from /usr/include/boost/range/iterator_range.hpp:13,
from /usr/include/boost/range/adaptor/transformed.hpp:16,
from deleteme.cpp:2:
/usr/include/boost/range/iterator_range_core.hpp: In instantiation of ‘SeqT boost::copy_range(const Range&) [with SeqT = std::array<long unsigned int, 2>; Range = boost::range_detail::transformed_range<<lambda(const auto:1&)
2> >]’:
deleteme.cpp:16:114: required from here
/usr/include/boost/range/iterator_range_core.hpp:842:20: error: no matching function for call to ‘std::array<long unsigned int, 2>::array(boost::range_detail::extract_const_iterator<boost::range_detail::transformed_range<<la
y<std::vector<int>, 2> >, true>::type, boost::range_detail::extract_const_iterator<boost::range_detail::transformed_range<<lambda(const auto:1&)>, std::array<std::vector<int>, 2> >, true>::type)’
842 | return SeqT( boost::begin( r ), boost::end( r ) );
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from deleteme.cpp:1:
/usr/include/c++/10.2.0/array:94:12: note: candidate: ‘std::array<long unsigned int, 2>::array()’
94 | struct array
| ^~~~~
/usr/include/c++/10.2.0/array:94:12: note: candidate expects 0 arguments, 2 provided
/usr/include/c++/10.2.0/array:94:12: note: candidate: ‘constexpr std::array<long unsigned int, 2>::array(const std::array<long unsigned int, 2>&)’
/usr/include/c++/10.2.0/array:94:12: note: candidate expects 1 argument, 2 provided
/usr/include/c++/10.2.0/array:94:12: note: candidate: ‘constexpr std::array<long unsigned int, 2>::array(std::array<long unsigned int, 2>&&)’
/usr/include/c++/10.2.0/array:94:12: note: candidate expects 1 argument, 2 provided
On the other hand, most surprisingly to me (!), if I force array_of_sizes to be a std::vector<std::size_t>, e.g.
auto array_of_sizes = boost::copy_range<std::vector<std::size_t>>( // vector instead of array
array_of_vectors | transformed(get_size)
);
it works! It looks like transformed turns a std::array<T,N> into a range convertible to std::vector<T>, just like it loses track of std::array's compile-time size.
What is this error/behavior due to?
I can only think that something is not working because of std::array's compile-time known size, as opposed to std::vector's run-time size. Probably transformed can't deal with that? Or maybe it's copy_range which can't?
If you compile with -std=c++2a, gcc 10.2 has a nice error message:
boost_1_74_0/boost/range/iterator_range_core.hpp:842:38: error: array must be initialized with a brace-enclosed initializer
842 | return SeqT( boost::begin( r ), boost::end( r ) );
| ~~~~~~~~~~~~^~~~~
The problem is that boost::copy_range only knows how to construct containers that take an iterator pair as (one of) their constructor parameters, so it is incompatible with std::array which does not actually have any constructors - it is only constructible as an aggregate from a (braced) list of elements.
With C++20's lambdas, you could write an alternate function that uses simple metaprogramming to produce that list of elements:
template<class T, class R>
T copy_range_fixed_size(R const& r) {
return [&r]<std::size_t... I>(std::index_sequence<I...>) {
auto it = boost::begin(r);
return T{(I, *it++)...};
}(std::make_index_sequence<T{}.size()>{});
}
Example.
I am trying to solve a simple Fibonacci problem using the lambda function, but I came across this error and I cant solve it.
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
string str;
auto N{0};
auto i{0};
cout<<"Digite o valor de N desejado: ";
getline(cin,str); //pega linha
stringstream(str) >> N;
if (N == 0){cout<<0;}
else if (N == 1){cout<<1;}
else
{
vector<int> v{0,1}; //cria vetor v
for_each(v.begin(),N,
[&](){
v.push_back(v[i]+v[i+1]);
i++;
});
i = 0;
for_each(v.begin(),N,
[&](){
cout<<v[i];
i++;
});
}
return 0;
}
And the error is the following:
quest1.cpp: In function ‘int main()’: quest1.cpp:30:4: error: no matching function for call to ‘for_each(std::vector<int>::iterator, int&, main()::<lambda()>)’ });
^ In file included from /usr/include/c++/6.3.1/algorithm:62:0,
from quest1.cpp:5: /usr/include/c++/6.3.1/bits/stl_algo.h:3763:5: note: candidate: template<class _IIter, class _Funct> _Funct std::for_each(_IIter,
_IIter, _Funct)
for_each(_InputIterator __first, _InputIterator __last, _Function __f)
^~~~~~~~ /usr/include/c++/6.3.1/bits/stl_algo.h:3763:5: note: template argument deduction/substitution failed: quest1.cpp:30:4: note: deduced conflicting types for parameter ‘_IIter’ (‘__gnu_cxx::__normal_iterator<int*, std::vector<int> >’ and ‘int’) });
^ quest1.cpp:38:5: error: no matching function for call to ‘for_each(std::vector<int>::iterator, int&, main()::<lambda()>)’
});
^ In file included from /usr/include/c++/6.3.1/algorithm:62:0,
from quest1.cpp:5: /usr/include/c++/6.3.1/bits/stl_algo.h:3763:5: note: candidate: template<class _IIter, class _Funct> _Funct std::for_each(_IIter,
_IIter, _Funct)
for_each(_InputIterator __first, _InputIterator __last, _Function __f)
^~~~~~~~ /usr/include/c++/6.3.1/bits/stl_algo.h:3763:5: note: template argument deduction/substitution failed: quest1.cpp:38:5: note: deduced conflicting types for parameter ‘_IIter’ (‘__gnu_cxx::__normal_iterator<int*, std::vector<int> >’ and ‘int’)
});
There's two problems in your code. One (already covered by other answers), you're passing the number of iterations as the second parameter to std::for_each, but it actually expects an end iterator. std::for_each(a, b, f) is designed to iterate from iterator a to iterator b and call f on each element in that range.
The second problem is more fundamental: if you modify the vector while iterating over it, you'll get Undefined Behaviour because any modification operation invalidates all iterators to the vector.
Looking at your code, it seems you want the first loop to a normal counting loop and not iteration over the container. The second loop could be done with for_each and a lambda:
vector<int> v{0,1};
for (int i = 0; i < N; ++i) {
v.push_back(v[i] + v[i+1]);
}
for_each(v.begin(), v.end(),
[](int element) {
cout << element;
}
);
Notice that the functor used in for_each is not nullary: the algorithm will pass the element to it.
Alternatively, the printing functionality could be implemented without lambdas:
copy(v.begin(), v.end(), ostream_iterator<int>(cout));
Or, if you prefer to keep the loop, you could just as well use a range-based for loop instead of for_each. The code will be shorter and [subjective]easier to read[/subjective]:
for (int elem : v) {
std::cout << elem;
}
std::for_each requires (as the error tries to tell you) an iterator where to start looping and an iterator where to end. You however are passing an iterator and an int, which are "conflicting types". If you want to loop over an whole vector do something like that:
std::vector<int> v{1, 2, 3};
std::for_each(v.begin(), // start at the front
v.end(), // loop over each element
[&] (int& i) {
i++;
});
If you just need to loop over a part of the vector do that
std::vector<int> v{1, 2, 3};
std::for_each(v.begin(), // start at the front
v.begin() + 2, // loop over the first two elements
[&] (int& i) {
i++;
});
You are not using the for_each function correctly. C++ does not know the signature you are using. Please refer to the documentation, e.g. for_each.
The compiler says exactly that. The second parameter of the for_each you are calling is of type int&, but the signature is for_each(InputIterator, InputIterator, Function) and not for_each(InputIterator, int&, Function), so it fails to compile.
I have been reading up on, how to perform a std::bind on a regular function.
And store the free function or member function into a std::function.
However, if I try to use a placeholder for one argument and an actual value for the other argument; I am not able to make a call(causes compilation error) to the std::function
So I tried the following code:
#include <random>
#include <iostream>
#include <memory>
#include <functional>
int g(int n1, int n2)
{
return n1+n2;
}
int main()
{
using namespace std::placeholders; // for _1, _2, _3...
std::function<int(int,int)> f3 = std::bind(&g, std::placeholders::_1, 4);
std::cout << f3(1) << '\n';
//this works just fine
auto f4 = std::bind(&g, std::placeholders::_1, 4);
std::cout << f4(1) << '\n';
}
I get the following error g++ 4.7
prog.cpp: In function 'int main()':
prog.cpp:17:22: error: no match for call to '(std::function<int(int, int)>) (int)'
std::cout << f3(1) << '\n';
^
In file included from /usr/include/c++/4.9/memory:79:0,
from prog.cpp:3:
/usr/include/c++/4.9/functional:2142:11: note: candidate is:
class function<_Res(_ArgTypes...)>
^
/usr/include/c++/4.9/functional:2434:5: note: _Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = int; _ArgTypes = {int, int}]
function<_Res(_ArgTypes...)>::
^
/usr/include/c++/4.9/functional:2434:5: note: candidate expects 2 arguments, 1 provided
If you're binding an argument to the function int g(int, int), what remains as a callable is a function taking one int as an argument, not two.
Try this:
std::function<int(int)> f3 = std::bind(&g, std::placeholders::_1, 4);
the type of your std::function should be:
std::function<int(int)> f3 = std::bind(&g, std::placeholders::_1, 4);
~~~
one argument
Your bind creates a function with one parameter. That's why you call f3 as this:
std::cout << f3(1) << '\n';
note: candidate expects 2 arguments, 1 provided
should have been your clue
How can I, or, can I, pass a template function to async?
Here is the code:
//main.cpp
#include <future>
#include <vector>
#include <iostream>
#include <numeric>
int
main
()
{
std::vector<double> v(16,1);
auto r0 = std::async(std::launch::async,std::accumulate,v.begin(),v.end(),double(0.0));
std::cout << r0.get() << std::endl;
return 0;
}
Here are the error messages:
^
a.cpp:13:88: note: candidates are:
In file included from a.cpp:1:0:
/usr/include/c++/4.8/future:1523:5: note: template std::future::type> std::async(std::launch, _Fn&&, _Args&& ...)
async(launch __policy, _Fn&& __fn, _Args&&... __args)
^
/usr/include/c++/4.8/future:1523:5: note: template argument deduction/substitution failed:
a.cpp:13:88: note: couldn't deduce template parameter ‘_Fn’
auto r0 = std::async(std::launch::async,std::accumulate,v.begin(),v.end(),double(0.0));
^
In file included from a.cpp:1:0:
/usr/include/c++/4.8/future:1543:5: note: template std::future::type> std::async(_Fn&&, _Args&& ...)
async(_Fn&& __fn, _Args&&... __args)
^
/usr/include/c++/4.8/future:1543:5: note: template argument deduction/substitution failed:
/usr/include/c++/4.8/future: In substitution of ‘template std::future::type> std::async(_Fn&&, _Args&& ...) [with _Fn = std::launch; _Args = {}]’:
a.cpp:13:88: required from here
/usr/include/c++/4.8/future:1543:5: error: no type named ‘type’ in ‘class std::result_of’
The problem is that to pass the second argument to std::async the compiler has to turn the expression &std::accumulate into a function pointer, but it doesn't know which specialization of the function template you want. To a human it's obvious you want the one that can be called with the remaining arguments to async, but the compiler doesn't know that and has to evaluate each argument separately.
As PiotrS.'s answer says, you can tell the compiler which std::accumulate you want with an explicit template argument list or by using a cast, or alternatively you can just use a lambda expression instead:
std::async(std::launch::async,[&] { return std::accumulate(v.begin(), v.end(), 0.0); });
Inside the body of the lambda the compiler performs overload resolution for the call to std::accumulate and so it works out which std::accumulate to use.
You have to disambiguate between possible instantiations by either explicitly passing the template arguments or using static_cast, so:
auto r0 = std::async(std::launch::async
, &std::accumulate<decltype(v.begin()), double>
, v.begin()
, v.end()
, 0.0);
or:
auto r0 = std::async(std::launch::async
, static_cast<double(*)(decltype(v.begin()), decltype(v.end()), double)>(&std::accumulate)
, v.begin()
, v.end()
, 0.0);