std::async fails in some msvc versions, workaround? - c++

The following code:
#include <vector>
#include <algorithm>
#include <thread>
#include <future>
#include <iostream>
int main() {
std::vector<int> v(1000);
for(unsigned i = 0; i < v.size(); i++) {
v[i] = i;
}
int bb = 2;
std::cout << v.back() << std::endl;
auto f = [&](int& x) {x = 2*x; bb=4; };
std::async(std::launch::async, std::for_each<decltype(v.begin()),decltype(f)>,
v.begin(), v.end(), f);
std::cout << v.back() << std::endl;
std::cout << "bb: " << bb;
return 0;
}
fails to compile with msvc version < 19.32.
e.g. the errors look like this with msvc = 19.29 (compiled on godbolt.org):
example.cpp
<source>(16): warning C4834: discarding return value of function with 'nodiscard' attribute
C:/data/msvc/14.31.31108/include\future(314): error C2280: 'main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37> &main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37>::operator =(const main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37> &)': attempting to reference a deleted function
<source>(14): note: see declaration of 'main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37>::operator ='
<source>(14): note: 'main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37> &main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37>::operator =(const main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37> &)': function was explicitly deleted
C:/data/msvc/14.31.31108/include\future(309): note: while compiling class template member function 'void std::_Associated_state<_Ty>::_Set_value_raw(_Ty &&,std::unique_lock<std::mutex> *,bool)'
with
[
_Ty=main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37>
]
C:/data/msvc/14.31.31108/include\future(305): note: see reference to function template instantiation 'void std::_Associated_state<_Ty>::_Set_value_raw(_Ty &&,std::unique_lock<std::mutex> *,bool)' being compiled
with
[
_Ty=main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37>
]
C:/data/msvc/14.31.31108/include\future(722): note: see reference to class template instantiation 'std::_Associated_state<_Ty>' being compiled
with
[
_Ty=main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37>
]
C:/data/msvc/14.31.31108/include\future(720): note: while compiling class template member function 'std::_State_manager<_Ty>::~_State_manager(void) noexcept'
with
[
_Ty=main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37>
]
C:/data/msvc/14.31.31108/include\future(879): note: see reference to function template instantiation 'std::_State_manager<_Ty>::~_State_manager(void) noexcept' being compiled
with
[
_Ty=main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37>
]
C:/data/msvc/14.31.31108/include\future(860): note: see reference to class template instantiation 'std::_State_manager<_Ty>' being compiled
with
[
_Ty=main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37>
]
<source>(17): note: see reference to class template instantiation 'std::future<main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37>>' being compiled
https://godbolt.org/z/WsovKcnnc
It is successfully compiled with gcc, icc, clang and msvc (>=19.32) (using -lpthread).
Is it possible to make it compile with msvc version = 19.29 (VS19) ?
I tried the option /std:c++latest but it did not make a difference.

If Marek R is right about the problem being MSVC's STL implementation, you may be able to avoid calling std::async by using std::packaged_task and std::thread instead.
#include <thread>
#include <future>
#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>
int main()
{
std::vector<int> v(100);
std::iota(v.begin(), v.end(), 0);
int bb = -2;
auto f = [&] (int& x) {
x = 2 * x;
bb = 4;
};
using Iter = decltype(v.begin());
using Fun = decltype(f);
auto foreach = [] (Iter begin, Iter end, Fun f) {
std::for_each<Iter, Fun>(begin, end, f);
};
std::packaged_task<void(Iter, Iter, Fun)> task(foreach);
auto future = task.get_future();
std::thread t(std::move(task), v.begin(), v.end(), f);
future.get();
t.join();
//
std::cout << v.back() std::endl;
std::cout << "bb: " << bb << std::endl;
return 0;
}

Related

Random number generation: compilation errors

I'm trying to adapt an example from Stroustrup C++ 4th Ed Page 1182, to call a function from operator()() vs the bind. Unfortunately, I'm getting a number of compilation errors. The code that worked before is // commented out. Does anyone know how to resolve the errors?
#include <iostream>
#include <random>
#include <map>
#include <functional>
using namespace std;
class rand_int {
public:
rand_int(int lo, int hi) : p{lo,hi}, re{rd()} {}
// int operator()() const { return r(); }
int operator()() const { return
uniform_int_distribution<>{p}(re); }
private:
uniform_int_distribution<>::param_type p;
random_device rd;
default_random_engine re;
// function<int()> r = bind(uniform_int_distribution<>{p}, re);
};
int main()
{
map<int,int> m;
rand_int ri{0,9};
for (int i=0; i < 100; ++i) {
m[ri()]++;
}
for (map<int,int>::iterator it = m.begin();
it != m.end(); ++it)
cout << it->first << ", " << it->second << '\n';
return 0;
}
Compilation:
clang++ -Wall -std=c++11 -pedantic test252.cc && ./a.out
In file included from test252.cc:2:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/random:49:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/random.h:35:
/usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/uniform_int_dist.h:243:25: error:
no matching function for call to object of type 'const
std::linear_congruential_engine<unsigned long, 16807, 0, 2147483647>'
__ret = __uctype(__urng()) - __urngmin;
^~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/uniform_int_dist.h:166:24: note:
in instantiation of function template specialization
'std::uniform_int_distribution<int>::operator()<const
std::linear_congruential_engine<unsigned long, 16807, 0, 2147483647> >'
requested here
{ return this->operator()(__urng, _M_param); }
^
test252.cc:12:35: note: in instantiation of function template specialization
'std::uniform_int_distribution<int>::operator()<const
std::linear_congruential_engine<unsigned long, 16807, 0, 2147483647> >'
requested here
uniform_int_distribution<>{p}(re); }
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/random.h:323:7: note:
candidate function not viable: 'this' argument has type 'const
std::linear_congruential_engine<unsigned long, 16807, 0, 2147483647>', but
method is not marked const
operator()()
^
This line:
uniform_int_distribution<>{p}(re);
modifies the member re. So the operator() can't be marked const.
You need to do:
int operator()() { // non-const method
return uniform_int_distribution<>{p}(re);
}
Here's a demo.

std::function of a value templated method compiles with clang and g++ but not with msvc

The following code compiles with clang v5.0.0 and g++ v8.1.0 but fails with visual studio (2013 and 2017):
#include <string>
#include <functional>
#include <iostream>
template <const char* name>
std::string fct() {
return name;
}
const char toto[] = "toto";
std::function<std::string()> fctptr = fct<toto>;
int main(){
std::cout << fctptr() << std::endl;
}
The error is the following:
main.cpp(11): error C2440: 'initializing' : cannot convert from 'std::string (__cdecl *)(void)' to 'std::function<std::string (void)>'
1> No constructor could take the source type, or constructor overload resolution was ambiguous
I tried to replace the std::function with a typedef to a function pointer, as such:
typedef std::string(*Fctptr)();
Fctptr fctptr = fct<toto>;
However, I got the same error.
Is it a bug with msvc compiler, or is the above code not standard compliant.
FWIW, the following failed to compile using g++ 6.4.0 (g++ -std=c++11).
#include <string>
#include <functional>
#include <iostream>
template <const char* name>
std::string fct() {
return name;
}
const char toto[] = "toto";
std::function<std::string()> fctptr = fct<toto>;
int main(){
std::cout << fctptr() << std::endl;
}
Here's the error message:
socc.cc:11:43: error: the value of ‘toto’ is not usable in a constant expression
std::function<std::string()> fctptr = fct<toto>;
^~~~
socc.cc:10:12: note: ‘toto’ was not declared ‘constexpr’
const char toto[] = "toto";
Changing the definition of toto to
constexpr char toto[] = "toto";
resolved the problem.

std::ref error in VS2015

#include <thread>
#include <iostream>
#include <functional>
struct C
{
void printMe() const
{}
};
struct D
{
void operator()() const
{}
};
int main()
{
D d;
std::thread t9(std::ref(d)); // fine
t9.join();
C c;
std::thread t8(&C::printMe, std::ref(c)); // error in VS2015
t8.join();
/*
1>C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\thr/xthread(238): error C2893: Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...)'
1> C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\thr/xthread(238): note: With the following template arguments:
1> C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\thr/xthread(238): note: '_Callable=void (__thiscall C::* )(void) const'
1> C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\thr/xthread(238): note: '_Types={std::reference_wrapper<C>}'
*/
}
http://ideone.com/bxXJem built without problems
Is the following code correct?
std::thread t8(&C::printMe, std::ref(c));
No, it doesn't compile. To compile it and make run it you need:
1) It needs to set the method printMe as a static method to send an its address (printMe's address), otherwise you are sending a relative address to instance C.
2) At the moment of create the thread t8, you are sending a reference to object C as an argument but the function printMe doesn't have arguments, So you need declare the argument into the printMe method.
3) As #cpplearner told you, send the pointer of the method as: std::thread t8(&C::printMe, &c);.
The resulting code is:
#include <thread>
#include <iostream>
#include <functional>
struct C
{
static void printMe(C* ref)
{
std::cout << "Address of C ref: " << std::hex << ref << std::endl;
}
};
struct D
{
void operator()() const
{
std::cout << "Operator D" << std::endl;
}
};
int main()
{
D d;
std::thread t9(std::ref(d)); // fine
t9.join();
C c;
std::thread t8(&C::printMe, &c); // Compile in VS2015
t8.join();
std::cout << "END" << std::endl;
}
And the output is:

proper way of setting up a packaged_task

When compiling the program below, I get the error message:
Error 1 error C2228: left of '.get_future' must have class/struct/union c:\users\haliaga\documents\visual studio 2010\projects\test\test\accumulateexceptionsafe.cpp 62 1 Test
which is not actually the real problem.
if you comment the lines:
//futures[i]=task.get_future();
//threads[i]=std::thread(std::move(task),block_start,block_end);
//block_start=block_end;
you'll get the warning below, that says that "tasK" was not called:
*warning C4930: 'std::packaged_task<> task(accumulate_block (__cdecl )(void))': prototyped function not called (was a variable definition intended?)
1> with
1> [
1> =int (std::_List_iterator>>,std::_List_iterator>>),
1> Iterator=std::_List_iterator>>,
1> T=int
1> ]
what would be the proper way of specifying:
std::packaged_task<T(Iterator,Iterator)> task(accumulate_block<Iterator,T>());
?
Thank you
PS: find below the code:
#include <list>
#include <numeric>
#include <vector>
#include <thread>
#include <future>
using namespace std;
template<typename Iterator,typename T>
struct accumulate_block
{
T operator()(Iterator first, Iterator last)
{
std::thread::id id = std::this_thread::get_id();
return std::accumulate(first, last, T());
}
};
class join_threads
{
std::vector<std::thread>& threads;
public:
explicit join_threads(std::vector<std::thread>& threads_):
threads(threads_)
{
std::thread::id id = std::this_thread::get_id();
}
~join_threads()
{
std::thread::id id = std::this_thread::get_id();
for(unsigned long i=0;i<threads.size();++i)
{
if(threads[i].joinable())
threads[i].join();
}
}
};
template<typename Iterator,typename T>
T parallel_accumulate(Iterator first,Iterator last,T init)
{
std::thread::id id = std::this_thread::get_id();
unsigned long const length=std::distance(first,last);
if(!length)
return init;
unsigned long const min_per_thread=25;
unsigned long const max_threads=(length+min_per_thread-1)/min_per_thread;
unsigned long const hardware_threads=std::thread::hardware_concurrency();
unsigned long const num_threads=std::min(hardware_threads!=0?hardware_threads:2,max_threads);
unsigned long const block_size=length/num_threads;
std::vector<std::future<T> > futures(num_threads-1);
std::vector<std::thread> threads(num_threads-1);
join_threads joiner(threads);
Iterator block_start=first;
for(unsigned long i=0;i<(num_threads-1);++i)
{
Iterator block_end=block_start;
std::advance(block_end,block_size);
std::packaged_task<T(Iterator,Iterator)> task(accumulate_block<Iterator,T>());
futures[i]=task.get_future();
threads[i]=std::thread(std::move(task),block_start,block_end);
block_start=block_end;
}
T last_result=accumulate_block<Iterator, T>()(block_start,last);
T result=init;
for(unsigned long i=0;i<(num_threads-1);++i)
{
result+=futures[i].get();
}
result += last_result;
return result;
};
int main()
{
list<int> l;
for(int i=0; i<26; ++i)
l.push_back(i);
std::thread::id id = std::this_thread::get_id();
int res = ::parallel_accumulate(l.begin(), l.end(), 0);
return 0;
}
Most vexing parse.
std::packaged_task<T(Iterator,Iterator)> task(accumulate_block<Iterator,T>());
declares a function called task that takes a parameter of type pointer to function taking no arguments and returning a accumulate_block<Iterator,T> and returns a std::packaged_task<T(Iterator,Iterator)>.
Disambiguate using the uniform initialization syntax:
std::packaged_task<T(Iterator,Iterator)> task(accumulate_block<Iterator,T>{});
Or with an extra pair of parentheses for ancient compilers that doesn't have support for uniform initialization:
std::packaged_task<T(Iterator,Iterator)> task((accumulate_block<Iterator,T>()));
// ^ ^

extern template class std::container of movable objects

I want to use new C++11 feature 'extern template class' with STL-container of movable objects (NOT copyable) and get compiler errors.
Example:
MyFile.hpp
#pragma once
#include <cstdio>
class MyFile
{
std::FILE * handle;
public:
MyFile(const char * filename);
~MyFile();
MyFile(MyFile && that);
MyFile & operator=(MyFile && that);
MyFile(const MyFile&) = delete;
void operator=(const MyFile&) = delete;
std::FILE const * getFile() const;
};
MyFile.cpp:
#include "MyFile.hpp"
#include <iostream>
MyFile::MyFile(const char * filename)
: handle{nullptr}
{
if (!(handle = fopen(filename, "r")))
throw std::runtime_error("blah blah blah");
}
MyFile::~MyFile()
{
std::cout << "File::~File()" << std::endl;
if (handle)
fclose(handle);
}
MyFile::MyFile(MyFile && that)
: handle{nullptr}
{
*this = std::move(that);
}
MyFile & MyFile::operator =(MyFile && that)
{
std::swap(handle, that.handle);
return *this;
}
const std::FILE * MyFile::getFile() const
{
return handle;
}
FileDeque.hpp:
#pragma once
#include <deque>
#include "MyFile.hpp"
extern template class std::deque<MyFile>;
using FileDeque = std::deque<MyFile>;
FileDeque.cpp:
#include "FileDeque.hpp"
template class std::deque<MyFile>;
And the test program:
#include
using namespace std;
#include "MyFile.hpp"
#include "FileDeque.hpp"
int main()
{
cout << "Hello World!" << endl;
{
FileDeque files;
files.emplace_back("C:/eula.1028.txt");
files.emplace_back("C:/eula.1031.txt");
files.emplace_back("C:/eula.2052.txt");
}
return 0;
}
With Visual Studio 2013 I get the following error:
D:\WinPrograms\Microsoft Visual Studio 12.0\VC\INCLUDE\deque(1714) : error C2280: 'MyFile::MyFile(const MyFile &)' : attempting to reference a deleted function
d:\devel\unique_ptr3\MyFile.hpp(18) : see declaration of 'MyFile::MyFile'
D:\WinPrograms\Microsoft Visual Studio 12.0\VC\INCLUDE\deque(1682) : while compiling class template member function 'void std::deque>::_Insert_n(std::_Deque_const_iterator>>,unsigned int,const MyFile &)'
with
[
_Ty=MyFile
]
D:\WinPrograms\Microsoft Visual Studio 12.0\VC\INCLUDE\deque(1510) : see reference to function template instantiation 'void std::deque>::_Insert_n(std::_Deque_const_iterator>>,unsigned int,const MyFile &)' being compiled
with
[
_Ty=MyFile
]
d:\devel\unique_ptr3\FileDeque.hpp(7) : see reference to class template instantiation 'std::deque>' being compiled
with
[
_Ty=MyFile
]
Generating Code...
It is clear that compiler tries to instantiate std::deque>::_Insert_n function that uses copying of objects, but why?
If std::deque is used directly in main.cpp I get no errrors:
#include <iostream>
#include <deque>
using namespace std;
#include "MyFile.hpp"
using FileDeque = std::deque<MyFile>;
int main()
{
cout << "Hello World!" << endl;
{
FileDeque files;
files.emplace_back("C:/eula.1028.txt");
files.emplace_back("C:/eula.1031.txt");
files.emplace_back("C:/eula.2052.txt");
}
return 0;
}
Also tried with clang and gcc and get similiar errrors.
So my questions:
Is it possible to make compiler not to instantiate container's class of movable objects? Why compiler tryies to instantiate methods that require copying support?
Do I want something wrong?
C++11 [temp.explicit]/8 states:
An explicit instantiation that names a class template specialization is also an explicit instantiation of the same kind (declaration or definition) of each of its members (not including members inherited from base classes) that has not been previously explicitly specialized in the translation unit containing the explicit instantiation, except as described below.
Since some of the members of std::deque<foo> require a copyable type foo - at the very least, the copy constructor - instantiating them is ill-formed. This is the cause of the errors you observe.
The workaround for this is to explicitly instantiate only the well-formed members that your program uses, something like:
// in FileDeque.hpp:
// Uncomment this to get linker errors suggesting
// other members to explicitly instantiate:
// extern template class std::deque<MyFile>;
extern template std::deque<MyFile>::deque();
extern template std::deque<MyFile>::~deque();
extern template auto std::deque<MyFile>::begin() -> iterator;
extern template auto std::deque<MyFile>::end() -> iterator;
// ...
// in FileDeque.cpp:
template std::deque<MyFile>::deque();
template std::deque<MyFile>::~deque();
template auto std::deque<MyFile>::begin() -> iterator;
template auto std::deque<MyFile>::end() -> iterator;
// ...