Odd behavior with std::async - c++

Consider the following sample code:
#include <future>
#include <array>
#include <cassert>
typedef std::array<int, 5> foo_t;
foo_t* bar(foo_t& foo) {
return &foo;
}
int main() {
foo_t foo;
auto a = std::async(bar, foo);
auto b = std::async(bar, foo);
assert(a.get() == b.get());
return 0;
}
GCC 4.6.3 compiles this with no complaints. However, this fails at runtime with:
test: test.cpp:15: int main(): Assertion `a.get() == b.get()' failed.
Aborted (core dumped)
GCC 4.8.2, however, refuses to compile the file:
In file included from /usr/local/include/c++/4.8.2/future:38:0,
from test.cpp:1:
/usr/local/include/c++/4.8.2/functional: In instantiation of 'struct std::_Bind_simple<std::array<int, 5ul>* (*(std::array<int, 5ul>))(std::array<int, 5ul>&)>':
/usr/local/include/c++/4.8.2/future:1525:70: required from 'std::future<typename std::result_of<_Functor(_ArgTypes ...)>::type> std::async(std::launch, _Fn&&, _Args&& ...) [with _Fn = std::array<int, 5ul>* (&)(std::array<int, 5ul>&); _Args = {std::array<int, 5ul>&}; typename std::result_of<_Functor(_ArgTypes ...)>::type = std::array<int, 5ul>*]'
/usr/local/include/c++/4.8.2/future:1541:36: required from 'std::future<typename std::result_of<_Functor(_ArgTypes ...)>::type> std::async(_Fn&&, _Args&& ...) [with _Fn = std::array<int, 5ul>* (&)(std::array<int, 5ul>&); _Args = {std::array<int, 5ul>&}; typename std::result_of<_Functor(_ArgTypes ...)>::type = std::array<int, 5ul>*]'
test.cpp:13:30: required from here
/usr/local/include/c++/4.8.2/functional:1697:61: error: no type named 'type' in 'class std::result_of<std::array<int, 5ul>* (*(std::array<int, 5ul>))(std::array<int, 5ul>&)>'
typedef typename result_of<_Callable(_Args...)>::type result_type;
^
/usr/local/include/c++/4.8.2/functional:1727:9: error: no type named 'type' in 'class std::result_of<std::array<int, 5ul>* (*(std::array<int, 5ul>))(std::array<int, 5ul>&)>'
_M_invoke(_Index_tuple<_Indices...>)
^
This appears to be a libstdc++ issue.
So my questions are:
1 - should GCC reject this code, or is there something in the standard that I am not aware of.
2 - should the assertion fail? The expected behavior is that async functions that take the same reference should refer to the same object, but it appears that a copy is made local to the async task.
I've tried compiling with clang, but it has the same compile error issues (as it shares the same libstdc++) with 4.8.2, and it can't compile the 4.6.3 library headers.

Yes, gcc should reject this code. std::async copies the arguments and forwards them as rvalues. You cannot bind an rvalue to an lvalue reference, so this fails. If you want to pass by reference use std::ref(foo). In this specific example, the call to std::async(bar,foo) essentially does the following:
template<typename F>
future<foo_t*> async(F& func,foo_t& arg){
F func_copy(func);
foo_t arg_copy(arg);
// on background thread
internal_set_future_result(func_copy(std::move(arg_copy)));
return ...;
}
If you use std::ref(foo) then the assertion should not fail. If the code doesn't compile then it's a moot point.

Related

Error while appling std::bind to function with argument <boost::asio::ip::tcp::socket>?

There's a function accepting an argument with type boost::asio::ip::tcp::socket. But I failed to apply std::bind to it. I've checked template arguments in std::_Bind_helper but no problem found. I've tried both gcc 8.1.0 and clang 6.0.0, and they give the same error.
#include <functional>
#include <boost/asio.hpp>
using namespace std;
namespace asio = boost::asio;
using tcp = asio::ip::tcp;
int c;
void good_f(int) {c=1;}
void good() {
using typeA = int;
auto helper = std::bind(&good_f, typeA(1));
helper();
// OK
}
void fixed_f(tcp::socket &) {c=1;}
void fixed() {
using type1 = tcp::socket;
asio::io_context ioc;
tcp::socket sock(ioc);
auto helper = std::bind(&fixed_f, std::ref(sock));
helper();
// OK
}
void fail_f(tcp::socket &&) {c=1;}
void fail() {
using type1 = tcp::socket;
asio::io_context ioc;
tcp::socket sock(ioc);
// fail_f(std::move(sock));
// OK
auto helper = std::bind(&fail_f, std::move(sock));
helper();
// a.cc:34:5: error: no matching function for call to object of type 'std::_Bind<void (*(boost::asio::basic_stream_socket<boost::asio::ip::tcp>))(boost::asio::basic_stream_socket<boost::asio::ip::tcp> &&)>'
// helper();
// ^~~~~~
}
Compilation log and errors:
recolic#RECOLICPC ~/tmp> clang++ --version
clang version 6.0.0 (tags/RELEASE_600/final)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
recolic#RECOLICPC ~/tmp> clang++ -c a.cc
a.cc:39:5: error: no matching function for call to object of type 'std::_Bind<void (*(boost::asio::basic_stream_socket<boost::asio::ip::tcp>))(boost::asio::basic_stream_socket<boost::asio::ip::tcp> &&)>'
helper();
^~~~~~
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.1.0/../../../../include/c++/8.1.0/functional:480:2: note: candidate template ignored: substitution failure [with _Args = <>]: no type named 'type' in 'std::result_of<void
(*&(boost::asio::basic_stream_socket<boost::asio::ip::tcp> &))(boost::asio::basic_stream_socket<boost::asio::ip::tcp> &&)>'
operator()(_Args&&... __args)
^
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.1.0/../../../../include/c++/8.1.0/functional:491:2: note: candidate template ignored: substitution failure [with _Args = <>]: no type named 'type' in 'std::result_of<void (*const &(const
boost::asio::basic_stream_socket<boost::asio::ip::tcp> &))(boost::asio::basic_stream_socket<boost::asio::ip::tcp> &&)>'
operator()(_Args&&... __args) const
^
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.1.0/../../../../include/c++/8.1.0/functional:509:2: note: candidate template ignored: substitution failure [with _Args = <>]: no type named 'type' in 'std::result_of<void (*volatile &(volatile
boost::asio::basic_stream_socket<boost::asio::ip::tcp> &))(boost::asio::basic_stream_socket<boost::asio::ip::tcp> &&)>'
operator()(_Args&&... __args) volatile
^
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.1.0/../../../../include/c++/8.1.0/functional:521:2: note: candidate template ignored: substitution failure [with _Args = <>]: no type named 'type' in 'std::result_of<void (*const volatile &(const volatile
boost::asio::basic_stream_socket<boost::asio::ip::tcp> &))(boost::asio::basic_stream_socket<boost::asio::ip::tcp> &&)>'
operator()(_Args&&... __args) const volatile
^
1 error generated.
I'm not sure what caused this error. Could you please give me any suggestions?
void fail_f_1(tcp::socket);
std::bind(&fail_f_1, tcp::socket(io_context));
This solution fails because boost::asio::ip::tcp::socket is noncopyable.
void fail_f_2(tcp::socket &&);
std::bind(&fail_f_2, std::move(tcp::socket(io_context)));
This solution fails because std::bind pass bound arguments as lvalues, rather than rvalue. fixed_f is a good solution.
If you have to pass rvalue-reference as bound argument, this answer will help.

Function from one library matched to template from another library

I'm working on a C++ project that uses two different libraries: spdlog for logging, and mutils-serialization for serializing objects to bytes (for sending over the network). Both libraries use namespaces properly, but when I attempt to write a program that uses both of them at the same time, my compiler (g++ 6.2) gives me nonsensical errors that seem to indicate it is attempting to instantiate a function template from the spdlog library by using the definition of a function template from the mutils library.
Here's my simple test program:
#include <spdlog/spdlog.h>
#include <spdlog/fmt/ostr.h>
#include "TestSerializableObject.h"
int main(int argc, char** argv) {
auto global_logger = spdlog::rotating_logger_mt("global_logger", "log", 1024 * 1024 * 500, 3);
global_logger->set_pattern("[%H:%M:%S.%e] [%l] %v");
global_logger->set_level(spdlog::level::trace);
std::shared_ptr<spdlog::logger> logger(spdlog::get("global_logger"));
auto message = std::make_shared<messaging::TestSerializableObject>(
1, 2, "A message!");
logger->trace("Received a message: {}", *message);
}
TestSerializableObject is a simple class that implements mutils::ByteRepresentable (the interface that enables serialization and pulls in the mutils-serialization library), and provides an operator<< (which is required for spdlog to be able to log it). I can post the code for it if necessary.
When I compile this with g++ -std=c++14 -I"./src" -I"./libraries" -I"./libraries/mutils/" -L"./libraries/" -O0 -g3 -Wall "src/LibraryCollisionTest.cpp", I get this long, ugly error (don't worry, I'll help you parse it):
In file included from ./libraries/mutils/mutils.hpp:3:0,
from ./libraries/mutils-serialization/SerializationSupport.hpp:2,
from src/TestSerializableObject.h:10,
from src/LibraryCollisionTest.cpp:10:
./libraries/mutils/args-finder.hpp: In instantiation of ‘struct mutils::function_traits<messaging::TestSerializableObject>’:
./libraries/mutils/args-finder.hpp:75:41: required from ‘auto mutils::convert(F) [with F = messaging::TestSerializableObject; ignore = void]’
./libraries/spdlog/fmt/bundled/format.h:1276:46: required from ‘struct fmt::internal::ConvertToInt<messaging::TestSerializableObject>’
./libraries/spdlog/fmt/bundled/format.h:1485:5: required by substitution of ‘template<class T> fmt::internal::MakeValue<Formatter>::MakeValue(const T&, typename fmt::internal::EnableIf<fmt::internal::Not<fmt::internal::ConvertToInt<T>::value>::value, int>::type) [with T = messaging::TestSerializableObject]’
./libraries/spdlog/fmt/bundled/format.h:2465:12: required from ‘static fmt::internal::Value fmt::internal::ArgArray<N, true>::make(const T&) [with Formatter = fmt::BasicFormatter<char>; T = messaging::TestSerializableObject; unsigned int N = 1u]’
./libraries/spdlog/fmt/bundled/format.h:2898:5: required from ‘void fmt::BasicWriter<Char>::write(fmt::BasicCStringRef<CharType>, const Args& ...) [with Args = {messaging::TestSerializableObject}; Char = char]’
./libraries/spdlog/details/logger_impl.h:69:9: required from ‘void spdlog::logger::log(spdlog::level::level_enum, const char*, const Args& ...) [with Args = {messaging::TestSerializableObject}]’
./libraries/spdlog/details/logger_impl.h:127:5: required from ‘void spdlog::logger::trace(const char*, const Args& ...) [with Args = {messaging::TestSerializableObject}]’
src/LibraryCollisionTest.cpp:21:53: required from here
./libraries/mutils/args-finder.hpp:12:37: error: ‘operator()’ is not a member of ‘messaging::TestSerializableObject’
: public function_traits<decltype(&T::operator())>
^~
./libraries/mutils/args-finder.hpp: In instantiation of ‘auto mutils::convert(F) [with F = messaging::TestSerializableObject; ignore = void]’:
./libraries/spdlog/fmt/bundled/format.h:1276:46: required from ‘struct fmt::internal::ConvertToInt<messaging::TestSerializableObject>’
./libraries/spdlog/fmt/bundled/format.h:1485:5: required by substitution of ‘template<class T> fmt::internal::MakeValue<Formatter>::MakeValue(const T&, typename fmt::internal::EnableIf<fmt::internal::Not<fmt::internal::ConvertToInt<T>::value>::value, int>::type) [with T = messaging::TestSerializableObject]’
./libraries/spdlog/fmt/bundled/format.h:2465:12: required from ‘static fmt::internal::Value fmt::internal::ArgArray<N, true>::make(const T&) [with Formatter = fmt::BasicFormatter<char>; T = messaging::TestSerializableObject; unsigned int N = 1u]’
./libraries/spdlog/fmt/bundled/format.h:2898:5: required from ‘void fmt::BasicWriter<Char>::write(fmt::BasicCStringRef<CharType>, const Args& ...) [with Args = {messaging::TestSerializableObject}; Char = char]’
./libraries/spdlog/details/logger_impl.h:69:9: required from ‘void spdlog::logger::log(spdlog::level::level_enum, const char*, const Args& ...) [with Args = {messaging::TestSerializableObject}]’
./libraries/spdlog/details/logger_impl.h:127:5: required from ‘void spdlog::logger::trace(const char*, const Args& ...) [with Args = {messaging::TestSerializableObject}]’
src/LibraryCollisionTest.cpp:21:53: required from here
./libraries/mutils/args-finder.hpp:75:41: error: ‘as_function’ is not a member of ‘mutils::function_traits<messaging::TestSerializableObject>’
return function_traits<F>::as_function(f);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~
In file included from ./libraries/spdlog/fmt/fmt.h:21:0,
from ./libraries/spdlog/common.h:41,
from ./libraries/spdlog/spdlog.h:12,
from src/LibraryCollisionTest.cpp:8:
./libraries/spdlog/fmt/bundled/format.h: In instantiation of ‘struct fmt::internal::ConvertToInt<messaging::TestSerializableObject>’:
./libraries/spdlog/fmt/bundled/format.h:1485:5: required by substitution of ‘template<class T> fmt::internal::MakeValue<Formatter>::MakeValue(const T&, typename fmt::internal::EnableIf<fmt::internal::Not<fmt::internal::ConvertToInt<T>::value>::value, int>::type) [with T = messaging::TestSerializableObject]’
./libraries/spdlog/fmt/bundled/format.h:2465:12: required from ‘static fmt::internal::Value fmt::internal::ArgArray<N, true>::make(const T&) [with Formatter = fmt::BasicFormatter<char>; T = messaging::TestSerializableObject; unsigned int N = 1u]’
./libraries/spdlog/fmt/bundled/format.h:2898:5: required from ‘void fmt::BasicWriter<Char>::write(fmt::BasicCStringRef<CharType>, const Args& ...) [with Args = {messaging::TestSerializableObject}; Char = char]’
./libraries/spdlog/details/logger_impl.h:69:9: required from ‘void spdlog::logger::log(spdlog::level::level_enum, const char*, const Args& ...) [with Args = {messaging::TestSerializableObject}]’
./libraries/spdlog/details/logger_impl.h:127:5: required from ‘void spdlog::logger::trace(const char*, const Args& ...) [with Args = {messaging::TestSerializableObject}]’
src/LibraryCollisionTest.cpp:21:53: required from here
./libraries/spdlog/fmt/bundled/format.h:1276:38: warning: invalid application of ‘sizeof’ to a void type [-Wpointer-arith]
enum { enable_conversion = sizeof(convert(get<T>())) == sizeof(Yes) };
The key line is here:
./libraries/mutils/args-finder.hpp: In instantiation of ‘auto mutils::convert(F)
[with F = messaging::TestSerializableObject; ignore = void]’:
./libraries/spdlog/fmt/bundled/format.h:1276:46: required from ‘struct
fmt::internal::ConvertToInt<messaging::TestSerializableObject>’
./libraries/spdlog/fmt/bundled/format.h:1485:5: required by substitution of
‘template<class T> fmt::internal::MakeValue<Formatter>::MakeValue(const
T&, typename fmt::internal::EnableIf<fmt::internal::Not<
fmt::internal::ConvertToInt<T>::value>::value, int>::type) [with T =
messaging::TestSerializableObject]’
Somehow, g++ has jumped from expanding a templated function inside the spdlog library, in namespace fmt::internal, to a function template in the mutils library, in namespace mutils, which is clearly not what the spdlog library intended to do! If I look at line 1276 of format.h, it's the one that calls the "convert" function inside this template struct:
template<typename T>
struct ConvertToInt
{
enum { enable_conversion = sizeof(convert(get<T>())) == sizeof(Yes) };
enum { value = ConvertToIntImpl2<T, enable_conversion>::value };
};
A few lines above, sure enough, is the function "convert":
template <typename T>
T &get();
Yes &convert(fmt::ULongLong);
No &convert(...);
These are all inside the namespace fmt::internal, and my IDE agrees that if I want the definition of the function "convert" on line 1276, I should jump to the function "convert" on line 1248. So why does g++ ignore this definition, and instead try to use the definition for mutils::convert(), which isn't even in the right namespace?
Note that clang also fails to compile this program, and makes the same mistake, so I don't think that this is a bug in g++.
This is definitively a bug in spdlog fmtlib, used internally by spdlog.
The problem is described summarily in this FAQ:
What is “Argument-Dependent Lookup” (aka ADL, or “Koenig Lookup”)?
Because messaging::TestSerializableObject inherits from a type in namespace mutils, when convert is called unqualified from inside namespace fmt::internal with a TestSerializableObject, both fmt::internal::convert and mutils::convert are considered in the overload set. Variadic functions always rank last during overload resolution, so the template argument F in the latter is a better match than the ... in the former and mutils::convert is chosen.
This is in no way specific to your code or to mutils – any type with a unary function or function template named convert in the same namespace or a parent namespace is susceptible to this problem.
The fix is to qualify the convert call and change the definition of fmt::internal::ConvertToInt<T>::enable_conversion from
enum { enable_conversion = sizeof(convert(get<T>())) == sizeof(Yes) };
to
enum { enable_conversion = sizeof(internal::convert(get<T>())) == sizeof(Yes) };
In my own code I make a habit of always qualifying all calls to functions inside any internal/detail namespace, even from code inside that same namespace, unless ADL usage is explicitly intended. (N.b. calls don't need to be fully qualified, merely qualified.) I learned this lesson from watching Boost have to deal with this problem the hard way as C++11 was emerging.

Test if Callable points at specific member function

I want to test if a _Callable __f is a (pointer to a) specific non-static member function memberfuncA.
I can test that with __f == &MyClass::memberfuncA, but only if I get no memberfuncB in the way, as in the example below, which results in a compiler error.
I tried to use std::is_convertible to make sure the cast will compile, but that didn't work; same with typeid().
#include <type_traits>
#include <typeinfo>
class A {};
class B {};
class MyClass {
public:
MyClass() {
A a;
B b;
push_exec(&MyClass::memberfuncA, this, a);
push_exec(&MyClass::memberfuncB, this, b);
}
template<typename _Callable, typename... _Args>
void push_exec(_Callable&& __f, _Args&&... __args)
{
// Test if typeid is the same
if(typeid(__f) == typeid(&MyClass::memberfuncA))
// Test if types are castable
if(std::is_convertible<typeof __f, typeof &MyClass::memberfuncA>::value)
// Test if __f is actually pointing to a specific member function (compiler error)
if(__f == &MyClass::memberfuncA)
return;
}
void memberfuncA(A a) { }
void memberfuncB(B b) { }
};
int main() {
MyClass mc;
}
Compiler output is
g++ --std=gnu++11 -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/callable_test.d" -MT"src/callable_test.o" -o "src/callable_test.o" "../src/callable_test.cpp"
../src/callable_test.cpp: In instantiation of ‘void MyClass::push_exec(_Callable&&, _Args&& ...) [with _Callable = void (MyClass::*)(B); _Args = {MyClass* const, B&}]’:
../src/callable_test.cpp:13:49: required from here
../src/callable_test.cpp:24:24: error: comparison between distinct pointer types ‘void (MyClass::*)(B)’ and ‘void (MyClass::*)(A)’ lacks a cast [-fpermissive]
if(__f == &MyClass::memberfuncA)
^
../src/callable_test.cpp:24:24: error: cannot convert ‘__f’ from type ‘void (MyClass::*)(B)’ to type ‘void MyClass::*’
../src/callable_test.cpp:24:24: error: cannot convert ‘&MyClass::memberfuncA’ from type ‘void (MyClass::*)(A)’ to type ‘void MyClass::*’
make: *** [src/callable_test.o] Error 1
Any idea how I can check if __f == &MyClass::memberfuncA?
If you really want compare __f and &MyClass::memberfunc, you can cast they to void *
if( ((void*)__f) == ((void*)&MyClass::memberfuncA) )
return;
Checking with std::is_convertible don't work because it's a compilation problem, not a run-time error. I mean: even if std::is_convertible value is false, the compiler try to compile the following if.
You could try std::is_convertible with SFINAE; something like this (EDIT: corrected version):
template<typename _Callable, typename... _Args>
typename std::enable_if<true == std::is_convertible<_Callable, void (MyClass::*)(A)>::value, void>::type push_exec(_Callable && __f, _Args && ... __args)
{
// do something
}
template<typename _Callable, typename... _Args>
typename std::enable_if<false == std::is_convertible<_Callable, void (MyClass::*)(A)>::value, void>::type push_exec(_Callable && __f, _Args && ... __args)
{
// do something else
}

How to wrap a call to `std::thread` constructor? (that works with gcc, VS and icpc)

Original Post (with errors)
I want to wrap a call to std::thread constructor (to keep track of all threads running so I can join them or do other things). In this example, the t1 thread gets constructed properly, but the t2 thread doesn't using gcc 4.8.1. However, on Windows (VS2012) it compiles without error and runs without error. Based on the discussion here, this may appear to be a bug in gcc, but arguably it is actually a bug in VS. What is the correct way of doing this?
#include <iostream>
#include <thread>
class A {
public:
void foo(int n ) { std::cout << n << std::endl; }
};
template<class F, class Arg>
std::thread& wrapper(F&& f, Arg&& a)
{
std::thread* t = new std::thread(f,a,100);
return *t;
}
int main()
{
A a;
std::thread t1(&A::foo, &a, 100);
t1.join();
std::thread t2 = wrapper(&A::foo, &a);
t2.join();
return 0;
}
Here is the compiler error
-bash-4.1$ make
g++ -std=c++11 main.cpp -o main
main.cpp: In function ‘int main()’:
main.cpp:23:41: error: use of deleted function ‘std::thread::thread(std::thread&)’
std::thread t2 = wrapper(&A::foo, &a);
^
In file included from main.cpp:2:0:
/opt/rh/devtoolset-2/root/usr/include/c++/4.8.1/thread:125:5: error: declared here
thread(thread&) = delete;
^
make: *** [all] Error 1
Update
I asked the wrong question here and am about to delete it, but because the answers are helpful, I will leave it. The problem was that the Intel icpc 14.0 compiler (not gcc 4.8.1) was throwing the same error regarding bind as discussed here. And it has nothing to do with the "wrapper" but just calling std::thread with a member function instead of static function.
The complaints about the memory leak are 100% valid, but that was me making an unfortunate simplification to the example (from my real code). The actual code saves the threads in a container and deletes the threads on destruction.
Here is a better example:
#include <iostream>
#include <thread>
class A {
public:
void foo() { }
template<class Function, class Arg>
std::thread* wrapper(Function&& f, Arg&& a)
{
auto t = new std::thread(f,a);
return t;
}
};
int main()
{
A a;
std::thread t1(&A::foo, &a);
t1.join();
std::thread* t2 = a.wrapper(&A::foo, &a);
t2->join();
delete t2;
return 0;
}
And the output for g++ (4.8.1) which works
-bash-4.1$ make CXX=g++
g++ -lpthread -std=c++11 main.cpp -o main
and the output for the Intel compiler icpc (14.0) which doesn't work
-bash-4.1$ make CXX=icpc
icpc -lpthread -std=c++11 main.cpp -o main
/opt/rh/devtoolset-2/root/usr/include/c++/4.8.1/functional(1697): error: class "std::result_of<std::_Mem_fn<void (A::*)()> (A *)>" has no member "type"
typedef typename result_of<_Callable(_Args...)>::type result_type;
^
detected during:
instantiation of class "std::_Bind_simple<_Callable (_Args...)> [with _Callable=std::_Mem_fn<void (A::*)()>, _Args=<A *>]" at line 1753
instantiation of "std::_Bind_simple_helper<_Callable, _Args...>::__type std::__bind_simple(_Callable &&, _Args &&...) [with _Callable=void (A::*)(), _Args=<A *>]" at line 137 of "/opt/rh/devtoolset-2/root/usr/include/c++/4.8.1/thread"
instantiation of "std::thread::thread(_Callable &&, _Args &&...) [with _Callable=void (A::*)(), _Args=<A *>]" at line 20 of "main.cpp"
/opt/rh/devtoolset-2/root/usr/include/c++/4.8.1/functional(1726): error: class "std::result_of<std::_Mem_fn<void (A::*)()> (A *)>" has no member "type"
typename result_of<_Callable(_Args...)>::type
^
detected during:
instantiation of class "std::_Bind_simple<_Callable (_Args...)> [with _Callable=std::_Mem_fn<void (A::*)()>, _Args=<A *>]" at line 1753
instantiation of "std::_Bind_simple_helper<_Callable, _Args...>::__type std::__bind_simple(_Callable &&, _Args &&...) [with _Callable=void (A::*)(), _Args=<A *>]" at line 137 of "/opt/rh/devtoolset-2/root/usr/include/c++/4.8.1/thread"
instantiation of "std::thread::thread(_Callable &&, _Args &&...) [with _Callable=void (A::*)(), _Args=<A *>]" at line 20 of "main.cpp"
compilation aborted for main.cpp (code 2)
make: *** [all] Error 2
-bash-4.1$
Your wrapper should be like this:
template<class F, class Arg>
std::thread wrapper(F&& f, Arg&& a)
{
return std::thread(std::forward<F>(f), std::forward<Arg>(a));
}
std::thread is not copyable. Given that wrapper returns a std::thread&, wrapper(&A::foo, &a); is an lvalue, and thus the initialisation of t2 requires a copy. That's what the compiler error is about.
Sadly, some versions of Visual Studio will happily perform a move here, even though there are no rvalues involved.
Something like std::thread* t = new std::thread(f,a,100); return *t; is pretty much the same as return *new std::thread(f,a,100);, and that clearly shows the memory leak operator: *new. Don't do this.
While not copyable, std::thread is movable. You just have to make it so that wrapper(&A::foo, &a); is an rvalue. That can be done simply by writing the function in the most natural style, like so:
template<class F, class Arg>
std::thread wrapper(F&& f, Arg&& a)
{
return std::thread(f, a, 100);
}
This however fails to correctly forward the arguments preserving their value category (as is, it turns rvalues into lvalues), even though it's not a problem for this particular example. In order to have general applicability, the function body should forward the arguments properly, like so: return std::thread(std::forward<F>(f), std::forward<Arg>(a), 100);.

C++11 with gcc 4.6.1 on a mac

I'm new to the mac and trying to get gcc 4.6 working.
I installed MacPorts and installed gcc 4.6.1 (by executing sudo port install gcc46). I'm trying to compile a simple test code that compiles fine on Linux (with gcc 4.6.1 and 4.6.2) and Windows, but I'm getting errors that make me thing there is something wrong with the installed libraries.
#include <iostream>
#include <type_traits>
#include <future>
struct test {
void get() {}
};
/*template<typename Func>
test async(const Func &f) {
f();
return test();
}*/
using namespace std;
int main (int argc, const char * argv[])
{
auto t1 = async([]() -> int{
cout << "This is thread 1" << endl;
return 1;
});
auto t2 = async([]() -> int {
cout << "This is thread 2" << endl;
return 2;
});
std::cout << "This is the main thread" << endl;
t1.get();
t2.get();
return 0;
}
The error messages:
macbook01:Test fozi$ g++ main.cpp -o test -std=c++0x
main.cpp: In function 'int main(int, const char**)':
main.cpp:30:6: error: invalid use of incomplete type 'std::enable_if<true, std::future<int> >::type'
/opt/local/include/gcc46/c++/future:111:11: error: declaration of 'std::enable_if<true, std::future<int> >::type'
main.cpp:30:6: error: unable to deduce 'auto' from '<expression error>'
main.cpp:35:6: error: invalid use of incomplete type 'std::enable_if<true, std::future<int> >::type'
/opt/local/include/gcc46/c++/future:111:11: error: declaration of 'std::enable_if<true, std::future<int> >::type'
main.cpp:35:6: error: unable to deduce 'auto' from '<expression error>'
/opt/local/include/gcc46/c++/future: At global scope:
/opt/local/include/gcc46/c++/future:150:5: error: 'typename std::enable_if<(! std::is_same<typename std::decay<_Functor>::type, std::launch>::value), std::future<decltype (declval<_Fn>()((declval<_Args>)()...))> >::type std::async(_Fn&&, _Args&& ...) [with _Fn = main(int, const char**)::<lambda()>, _Args = {}, typename std::enable_if<(! std::is_same<typename std::decay<_Functor>::type, std::launch>::value), std::future<decltype (declval<_Fn>()((declval<_Args>)()...))> >::type = std::future<int>]', declared using local type 'main(int, const char**)::<lambda()>', is used but never defined [-fpermissive]
/opt/local/include/gcc46/c++/future:150:5: error: 'typename std::enable_if<(! std::is_same<typename std::decay<_Functor>::type, std::launch>::value), std::future<decltype (declval<_Fn>()((declval<_Args>)()...))> >::type std::async(_Fn&&, _Args&& ...) [with _Fn = main(int, const char**)::<lambda()>, _Args = {}, typename std::enable_if<(! std::is_same<typename std::decay<_Functor>::type, std::launch>::value), std::future<decltype (declval<_Fn>()((declval<_Args>)()...))> >::type = std::future<int>]', declared using local type 'main(int, const char**)::<lambda()>', is used but never defined [-fpermissive]
Note that if I use my dummy async function it compiles and runs fine.
I'm kind of stuck, do I have to install a specific library (version)? How do I do that?
I've had similar issues with gcc-4.6.1 and OS X 10.6. The problem is C++0x's thread is not supported at the moment on OS X.
See this post: c++0x, std::thread error (thread not member of std)
If you look in "${prefix}/include/c++/4.6.1/future" header file, you'll see the line:
#if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1) \
&& defined(_GLIBCXX_ATOMIC_BUILTINS_4)
Unfortunately, _GLIBCXX_HAS_GTHREADS evalute to 0 on OS X.
We're getting there
gcc 4.7 (port) compiles this code just fine.
Xcode 4.3 comes with clang 3.1 which is supposed to support this, but it crashes when I try to compile. However I built clang from SVN and replaced the compiler Xcode is using and now it compiles and runs fine as well.
And it only took half a year.
Try g++ -v to get the version of G++ you're using. I'm not using a pre-compiled compiler but perhaps it is the same for you.
The GCC 4.6.0 is installed in /usr/local/bin under the name x86_64-apple-darwin10.7.0-g++
If you still use the simple g++ command, it may still be /usr/bin/g++, which is Apple's llvm-gcc flavor.