EDIT: added the compiler errors at the end.
First I'll say I have both Visual Studio Express 2013 and CodeBlocks (Mingw w64) set up and running.
But I am having a problem with some code compiling with one compiler but not the other and vis-versa.
Consider this code:
void foo(std::string& s){
std::cout << "in foo function now" << std::endl;
s = "the new string.";
}
int main(){
std::string s = "the original string";
std::thread t1(foo, std::ref(s));
t1.join();
if (!s.size()) std::cout << "s is empty" << std::endl;
else std::cout << s << std::endl;
std::cin.get();
return 0;
}
It compiles and runs fine on both GCC and VS.
BUT if I decide to change std::ref(s) with std::move(s) it won't compile with GCC anymore but it will with VS.
To fix it I have to add a '&' so void foo(std::string& s) becomes void foo(std::string&& s), THEN it will compile with gcc but it won't with VS anymore!
My guess would be that the VS compiler is quiet forgiving and is not following the standard to the letter but I haven't withness such a behavior with std::function and std::bind even though the arguments are passed the same way I believe.
At any rate I would very much appreciate some help in understanding what is going on.
EDIT: The errors:
The GCC one:
C:/mingw-w64/x86_64-5.1.0-posix-seh-rt_v4-rev0/mingw64/x86_64-w64-mingw32/include/c++/functional:1505:61: error: no type named 'type' in 'class std::result_of<void (*(std::__cxx11::basic_string<char>))(std::__cxx11::basic_string<char>&)>'
typedef typename result_of<_Callable(_Args...)>::type result_type;
^
C:/mingw-w64/x86_64-5.1.0-posix-seh-rt_v4-rev0/mingw64/x86_64-w64-mingw32/include/c++/functional:1526:9: error: no type named 'type' in 'class std::result_of<void (*(std::__cxx11::basic_string<char>))(std::__cxx11::basic_string<char>&)>'
_M_invoke(_Index_tuple<_Indices...>)
The VS one:
Error 1 error C2664: 'void (std::string &&)' : cannot convert argument 1 from 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>' to 'std::string &&' c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional 1149 1 Tests
MSVC is wrong, both under the standard and practically.
Internally, they both copy the arguments into something tuple-like, the unpack them in the spawned thread and a call is made.
Under the standard, the invoke expression must pass the values as rvalues into the called function after copying them (well, except for std::ref cases).
This is because of the wording of the INVOKE clause in this standard. I've talked about it before here, but have not tracked it down yet.
Logically, the value in the tuple is never going to be used again, so it should be in an rvalue context not an lvalue one. Taking something by value, copying it, then passing it by reference, then throwing out the copy, is usually a bug.
Related
I am trying to make some working threads for some (quite) intensive signal processing tasks. I use C++20 for the moment to use std::jthread which I prefer over std::thread (although this is not restrictive and I don't think is related to my problem).
I would like to pass an std::barrier to a "worker function" called from some std::jthreads. If I set as argument in the "worker function" std::barrier<>& (which creates an std::barrier without a completion function) everything seems to be OK. I would like to pass an std::barrier with a custom completion function (a lambda at the moment but it may end up being a named function). I haven't managed to do that and I get compilation errors.
A working (actually it is not even compiling) example to replicate the problem is
#include <thread>
#include <barrier>
int main() {
std::barrier barrier(5, []() noexcept {std::cout << "Completion reached\n\n";}); // num of threads and completion function
std::array<std::jthread> threads{};
for (auto& thread : threads)
thread = std::jthread(workerFunction, std::ref(barrier)); // Worker function (see below) and reference to the barrier
return 0;
}
As a "worker" function I have the following dummy (for testing purposes)
void worker(std::stop_token stopToken, std::barrier<void(void)>& barrier) noexcept { // Most probably the issue is here at the std::barrier<void(void)>&
while (!stopToke.stop_requested()) {
// Do some processing and stuff (at the moment just some dummy increments)
barrier.arrive_and_wait();
}
std::cout << "Termination requested for thread " << std::this_thread::get_id() << '\n';
barrier.arrive_and_drop();
}
At the moment I am working on Microsoft Visual Studio 2022 Community Edition (version 17.4.4) and compile (or at least try to) in debug mode.
The error I get is (where I have put some empty lines in between for clarity)
1>C:\Program Files\Microsoft Visual >Studio\2022\Community\VC\Tools\MSVC\14.34.31933\include\barrier(76,13): error C2338: static_assert >failed: 'N4861 [thread.barrier.class]/5: is_nothrow_invocable_v<CompletionFunction&> shall be true'
1>C:\Users\Aris\Documents\Development\Perception Neuron\DSP\TestBarrier.cpp(27,16): message >: see reference to class template instantiation 'std::barrier<void (void)>' being compiled
1>C:\Program Files\Microsoft Visual >Studio\2022\Community\VC\Tools\MSVC\14.34.31933\include\xmemory(1395,1): error C2207: >'std::_Compressed_pair<_Ty1,_Ty2,false>::_Myval1': a member of a class template cannot acquire a >function type
1>C:\Program Files\Microsoft Visual >Studio\2022\Community\VC\Tools\MSVC\14.34.31933\include\barrier(186,44): message : see reference to >class template instantiation >'std::_Compressed_pair<_Completion_function,std::barrier<_Completion_function>::_Counter_t,false>' >being compiled
1> with
1> [
1> _Completion_function=void (void)
1> ]
If I pass a lambda function to the thread instead, everything seems to work without errors or warnings. For example, completely dropping the worker() and instead do
#include <thread>
#include <barrier>
int main() {
std::barrier barrier(5, []() noexcept {std::cout << "Completion reached\n\n";}); // num of threads and completion function
std::array<std::jthread> threads{};
for (auto& thread : threads)
thread = std::jthread([&barrier] (std::stop_token stopToken) {
while (!stopToken.stopRequested()) {
// Do the same stuff
barrier.arrive_and_wait();
}
std::cout << "Termination requested for thread " << std::this_thread::get_id() << '\n';
barrier.arrive_and_drop();
});
return 0;
}
compiles and runs with intended behavior (or at least I haven't noticed anything unusual so far).
Any help and clarification would be most welcome.
First, you should pass a pointer-to-function type, not a function type directly, as the template argument for std::barrier:
std::barrier<void(*)(void)>&
The you also forgot to add noexcept to the function type void(void) (aka void()). noexcept is part of the type and here relevant because std::barrier requires a callable that is nothrow-invocable.
std::barrier<void(*)(void) noexcept>&
Because you are passing the barrier object to the function you also need to make sure that the type in main is the same. CTAD will deduce a different type because each lambda has a different type. So just std::barrier without template argument list doesn't work there. (The alternative would be to template worker on a template parameter T and then take a std::barrier<T>& as argument.)
I was looking at an answer to another question. However I can't figure out, based on that example, why can't I bind a value of some local variable with MSVC 2015 compiler? It just throws an error while gcc 5.3 compiles it fine on msys2/mingw64. I mean like in
#include <iostream>
#include <functional>
#include <vector>
int add(int a, int b) { return a + b; }
using bound_add_t = decltype(std::bind(add, std::placeholders::_1, int()));
int main() {
std::vector<bound_add_t> vec;
int y = 2;
vec.emplace_back(add,std::placeholders::_1, y); // <- this causes the problem
vec.emplace_back(add,std::placeholders::_1, 2);
vec.emplace_back(add,std::placeholders::_1, 3);
for (auto &b : vec)
std::cout << b(5) << std::endl;
return 0;
}
Severity Code Description Project File Line Suppression State
Error C2664 'std::_Binder &,int>::_Binder(std::_Binder &,int> &&)': cannot convert argument 3 from 'int' to 'int &&' C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xmemory0 655
Is it a known issue tracked somewhere? I'm not even sure what is the underlying problem here. Is there a workaround?
In my use case, I'm missing one argument that becomes available later, so I'd want to have a vector with a wrapped function ready just like in that example.
Update
Is it a C++14 thing? I was poking around on http://ideone.com/Zi1Yht . While there is no MSVC, only compiler marked as C++14 was able to compile it.
Update 2
I tried
std::vector<std::function<int(int)> > vec;
vec.emplace_back(add, std::placeholders::_1, y);
if that was implied, I get
Severity Code Description Project File Line Suppression State
Error C2664 'std::function::function(std::function &&)': cannot convert argument 1 from 'int (__cdecl &)(int,int)' to 'std::allocator_arg_t' C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xmemory0 655
MSVC is in its right in rejecting this code. int() is a temporary and therefore corresponding Args&&... parameter is deduced as int&&. So the constructor of the result type of bind can take int&& as the last parameter, and y is not an rvalue so compilation fails.
This is not a bug in other compilers, because the result of bind is unspecified.
If you don't want to fall back to std::function you can enforce the type of the last parameter to be const int&:
using bound_add_t = decltype(std::bind(add, std::placeholders::_1, std::declval<const int&>()));
The return type of std::bind is unspecified.
The required constructor is the copy constructor or the move constructor.
Construct it from the arguments (function, placeholders, ...) you give is unspecified and may work for specific implementation but is not portable.
As a workaround, you may do
std::vector<std::function<int(int)> > vec;
int y = 2;
vec.push_back(std::bind(add, std::placeholders::_1, y));
vec.push_back(std::bind(add, std::placeholders::_1, 2));
vec.push_back(std::bind(add, std::placeholders::_1, 3));
I encountered a compiler crash and intellisense false positives with Visual Studio 2015 using C++.
This crashes the compiler when written within a function block:
if();
This is the dialog that is shown when compiling (I am on a German version of Windows):
Even though the compiler crashes, I get error list output:
Error C2059 syntax error: ')'
Warning C4390 ';': empty controlled
statement found; is this the intent?
Error C1903 unable to recover from previous error(s); stopping compilation
This produces squiggles and error annotations in the vertical scrollbar in map mode, but no actual intellisense errors:
#include <vector>
struct S { std::vector<S> Children; };
int main(int argc, char* argv[]) {
S item;
item.Children.push_back(S());
// ^
// Error: no instance of overloaded function
// "std::vector<_Ty, _Alloc>::push_back [with _Ty=S, _Alloc=std::allocator<S>]"
// matches the argument list
// argument types are: (S)
// object type is: std::vector<S, std::allocator<S>>
S& back = item.Children.back();
// ^^^^
// Error: a reference of type "S &" (not const-qualified) cannot be
// initialized with a value of type "S"
return 0;
}
Are those bugs? Are they known? Can you reproduce them?
For the first case: the compiler shouldn't crash but just issue the diagnostic you show. So yes, that's a bug. Which doesn't occur in VS2013 btw. Submit a report for it here
For the second case: it is the same in VS2013 and is due to nesting a vector of S inside S. This and other cases make the error squiggles appear incorrectly, it is actually not that uncommon. But ideally it should not happen so you can submit a bug report for it as well, though it might be something which is going to be labelled 'wontfix' as the compiler team usually focusses on more urgent cases.
I found out that a std::packaged_task couldn't be pushed into a std::vector if the parameter type returns void in Visual Studio (2012, 2013, Nov 2013 CTP). For example,
typedef std::packaged_task<void()> packaged_task;
std::vector<packaged_task> tasks;
packaged_task package;
tasks.push_back(std::move(package));
The error messages are:
error C2182: '_Get_value' : illegal use of type 'void'
error C2182: '_Val' : illegal use of type 'void'
error C2182: '_Val' : illegal use of type 'void'
error C2512: 'std::_Promise<int>' : no appropriate default constructor available
error C2665: 'std::forward' : none of the 2 overloads could convert all the argument types
I think this is bug because this code snippet works if
the return type is not void,
it is compiled in XCode.
Are there solutions or other options in Visual Studio? I know that boost can be used to replace this.
I can reproduce this with a simple auto m = std::move(package);.
int main()
{
typedef std::packaged_task<void()> packagedtask;
packagedtask p1;
packagedtask p2;
p2 = std::move(p1); // does not cause the error
auto p3 = std::move(p2); // causes the error
}
Trawling through the code, packaged_task has embedded typedefs as follows;
typedef typename _P_arg_type<_Ret>::type _Ptype;
typedef _Promise<_Ptype> _MyPromiseType;
_P_arg_type offers a non-void type when the return type is void. The packaged_task move constructor contains a reference to the internal _Promise as _Promise<_Ret>;
_MyPromise(_STD forward<_Promise<_Ret> >(_Other._MyPromise))
This then becomes _Promise<void> which in turn generates further invalid code that generates the list of errors seen. It should probably be;
_MyPromise(_STD forward<_MyPromiseType >(_Other._MyPromise))
// possibly even using a move
As the move assignment operator does.
As a workaround, consider adding a "dummy" or "unusable" return type of some sort;
struct unusable {};
Or just simply an int or boost as you have already suggested.
I have been developing a library that is getting pretty large, and now I am adding some template-based parts that use C++0x features. So I tried to compile my library (which compiled entirely without warnings on the current standard) with the flag -std=c++0x using gcc version 4.4.5 (on Linux). Now I got a huge influx of error messages related to the conversion of "temporaries" variables to non-const references. The problem is, they are not temporary!
Here is a small piece of code that reproduces the error:
#include <iostream>
#include <map>
struct scanner {
scanner& operator &(std::pair<std::string, int&> i) {
std::cout << "Enter value for " << i.first << ": ";
std::cin >> i.second;
return *this;
};
};
struct vect {
int q[3];
void fill(scanner& aScan) {
aScan & std::pair<std::string, int&>("q0",q[0])
& std::pair<std::string, int&>("q1",q[1])
& std::pair<std::string, int&>("q2",q[2]);
};
};
int main() {
vect v;
scanner s;
v.fill(s);
return 0;
};
If you compile this with the current standard (no c++0x flag) it will compile and run as expected. However, if you compile it with -std=c++0x, it will throw the following error at compile-time:
/usr/include/c++/4.4/bits/stl_pair.h:94: error: invalid initialization of non-const reference of type ‘int&’ from a temporary of type ‘int’
I really can't figure this out. I have looked over the web and SO, but none seem to have this problem. Is it a bug in std::pair? I would really like to know what the problem is.. thank you for any insight you can give.
PS: don't complain about the "quality" or "stupidity" of the code above, it is not real code.. just an example that shows the error.
Your code is not valid C++03, comeau gives (after adding a return statement to op&):
"stl_pair.h", line 44: error: qualifiers dropped in binding reference of
type "int &" to initializer of type "const int"
pair(const _T1& __a, const _T2& __b) : first(__a), second(__b) {}
^
detected during instantiation of "std::pair<_T1, _T2>::pair(const
_T1 &, const _T2 &) [with _T1=std::string, _T2=int &]" at
line 17 of "ComeauTest.c"
...
The problem is a reference inside a pair. If I remember correctly, it is a gcc extension that allows this. Gcc does accept it with -std=gnu++98, which is the default for C++, but with -std=c++98, gcc 4.4.3 gives:
In file included from /usr/include/c++/4.4/bits/stl_algobase.h:66,
from /usr/include/c++/4.4/algorithm:61,
from PREAMBLE:7:
/usr/include/c++/4.4/bits/stl_pair.h: In instantiation of ‘std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, int&>’:
<input>:5: instantiated from here
/usr/include/c++/4.4/bits/stl_pair.h:83: error: forming reference to reference type ‘int&’
...
There are LOTS of bugs in gcc C++0x support, it's very much unfinished and development is ongoing. This is doubly true for a version as old as gcc-4.4.5. If you're serious about starting C++0x development before the standard is ratified, you need to use the bleeding-edge version of the compiler and standard library.
It compiles fine both with and without -std=c++0x with GCC 4.5.2.
I guess GCC 4.4.5 doesn't support C++0x that much to get this working.
Except for the missing return *this; in scanner& operator &(std::pair<std::string, int&> i), your code is valid C++0x.