I have a class hierarchy like this one (this is the actual class but I cleaned it up):
class Notifiable
{
public:
void notify();
}
template <class Exp>
class Batch : public Notifiable
{
public:
void run();
}
void Batch<Exp>::run()
{
done.clear();
generator->resetGeneration();
while(generator->hasMoreParameters())
{
// Lock for accessing active
std::unique_lock<std::mutex> lock(q_mutex, std::adopt_lock);
// If we've less experiments than threads
if (active.size() < threads)
{
Configuration conf = generator->generateParameters();
Exp e(executable, conf);
//std::weak_ptr<Batch<Exp>> bp;
//bp.reset(this);
std::thread t(&Exp::run, e, *this);
std::thread::id id = t.get_id();
active.insert(id);
t.detach();
}
q_control.wait(lock, [this] { return active.size() < threads; } );
}
}
class Experiment
{
public:
void run(Notifiable& caller)
{
do_stuff();
caller.notify();
}
virtual void do_stuff() = 0;
}
class MyExperiment : public Experiment
{
public:
void do_stuff()
{
// do my stuff
}
}
I then instantiate a Batch<MyExperiment> object and call run(), using this code:
Batch<ELExperiment> b(pex, options["name"].as<string>(), options["executable"].as<string>());
b.run();
but I get this at compile-time:
In file included from /opt/local/include/gcc47/c++/bits/move.h:57:0,
from /opt/local/include/gcc47/c++/bits/stl_pair.h:61,
from /opt/local/include/gcc47/c++/bits/stl_algobase.h:65,
from /opt/local/include/gcc47/c++/bits/char_traits.h:41,
from /opt/local/include/gcc47/c++/ios:41,
from /opt/local/include/gcc47/c++/ostream:40,
from /opt/local/include/gcc47/c++/iostream:40,
from json2cli/main.cpp:9:
/opt/local/include/gcc47/c++/type_traits: In instantiation of 'struct std::_Result_of_impl<false, false, std::_Mem_fn<void (Experiment::*)(Notifiable&)>, MyExperiment, Batch<MyExperiment> >':
/opt/local/include/gcc47/c++/type_traits:1857:12: required from 'class std::result_of<std::_Mem_fn<void (Experiment::*)(Notifiable&)>(MyExperiment, Batch<MyExperiment>)>'
/opt/local/include/gcc47/c++/functional:1563:61: required from 'struct std::_Bind_simple<std::_Mem_fn<void (Experiment::*)(Notifiable&)>(MyExperiment, Batch<MyExperiment>)>'
/opt/local/include/gcc47/c++/thread:133:9: required from 'std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (Experiment::*)(Notifiable&); _Args = {MyExperiment&, Batch<MyExperiment>&}]'
json2cli/batch.hh:86:46: required from 'void Batch<Exp>::run() [with Exp = MyExperiment]'
json2cli/main.cpp:113:15: required from here
/opt/local/include/gcc47/c++/type_traits:1834:9: error: no match for call to '(std::_Mem_fn<void (Experiment::*)(Notifiable&)>) (MyExperiment, Batch<MyExperiment>)'
In file included from /opt/local/include/gcc47/c++/memory:81:0,
from json2cli/parameterexpression.hh:19,
from json2cli/main.cpp:13:
/opt/local/include/gcc47/c++/functional:525:11: note: candidates are:
/opt/local/include/gcc47/c++/functional:548:7: note: _Res std::_Mem_fn<_Res (_Class::*)(_ArgTypes ...)>::operator()(_Class&, _ArgTypes ...) const [with _Res = void; _Class = Experiment; _ArgTypes = {Notifiable&}]
/opt/local/include/gcc47/c++/functional:548:7: note: no known conversion for argument 1 from 'MyExperiment' to 'Experiment&'
/opt/local/include/gcc47/c++/functional:553:7: note: _Res std::_Mem_fn<_Res (_Class::*)(_ArgTypes ...)>::operator()(_Class*, _ArgTypes ...) const [with _Res = void; _Class = Experiment; _ArgTypes = {Notifiable&}]
/opt/local/include/gcc47/c++/functional:553:7: note: no known conversion for argument 1 from 'MyExperiment' to 'Experiment*'
/opt/local/include/gcc47/c++/functional:559:2: note: template<class _Tp> _Res std::_Mem_fn<_Res (_Class::*)(_ArgTypes ...)>::operator()(_Tp&, _ArgTypes ...) const [with _Tp = _Tp; _Res = void; _Class = Experiment; _ArgTypes = {Notifiable&}]
/opt/local/include/gcc47/c++/functional:559:2: note: template argument deduction/substitution failed:
In file included from /opt/local/include/gcc47/c++/bits/move.h:57:0,
from /opt/local/include/gcc47/c++/bits/stl_pair.h:61,
from /opt/local/include/gcc47/c++/bits/stl_algobase.h:65,
from /opt/local/include/gcc47/c++/bits/char_traits.h:41,
from /opt/local/include/gcc47/c++/ios:41,
from /opt/local/include/gcc47/c++/ostream:40,
from /opt/local/include/gcc47/c++/iostream:40,
from json2cli/main.cpp:9:
/opt/local/include/gcc47/c++/type_traits:1834:9: note: cannot convert 'std::declval<Batch<MyExperiment> >()' (type 'Batch<MyExperiment>') to type 'Notifiable&'
It looks like I can’t just expect to generalize any Batch<Exp> into a Notifiable for function calling. Can you confirm that?
Update sorry, I thought I could avoid dumping all of my code inside the question, but in fact there must be something wrong in the way I spawn the thread for Batch<Exp>::run(). There are still a couple of details missing, but I don’t really think they are related (e.g. how I generate the parameters for the experiment).
Thanks
Your error is not in the code that you show to us, Some where in the code you try to bind your
runand create a thread usingstd::threadand that’s the problem, since it can’t create a correct struct for your bound function and simplest workaround is to write your own wrapper:And then use your own wrapper to start the function, I can’t say for sure but I think this is a bug in compiler (all compilers have this bug: GCC, MSVC, …) that when you expression get complicated they fail to use it in
std::bind!!