【问题标题】:Why can't references to instantiated an class template A which inherits from (non-template) class B be converted to references to B?为什么不能将继承自(非模板)类 B 的实例化类模板 A 的引用转换为对 B 的引用?
【发布时间】:2012-10-16 08:58:22
【问题描述】:

我有一个像这样的类层次结构(这是实际的类,但我清理了它):

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
   }
}

然后我实例化一个Batch&lt;MyExperiment&gt; 对象并调用run(),使用以下代码:

Batch<ELExperiment> b(pex, options["name"].as<string>(), options["executable"].as<string>());
    b.run();

但我在编译时得到了这个:

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&'

看来我不能期望将任何Batch&lt;Exp&gt; 概括为Notifiable 以进行函数调用。你能确认一下吗?

更新抱歉,我以为我可以避免将我的所有代码转储到问题中,但实际上我为Batch&lt;Exp&gt;::run() 生成线程的方式一定有问题。仍然缺少一些细节,但我认为它们并不相关(例如,我如何为实验生成参数)。

谢谢

【问题讨论】:

  • "然后我实例化一个 Batch 对象并调用 run()," 为什么不向我们展示这段代码呢?
  • ´Batch b(); b.run();'
  • Batch&lt;MyExperiment&gt; b(); --> Batch&lt;MyExperiment&gt; b;。今天是最令人烦恼的解析日 - 请参阅今天的问题:stackoverflow.com/questions/12911078/…
  • @tunnuz 你应该把你实例化和运行的行放在问题本身中。
  • @juanchopanza 我刚刚添加了 Batch::run() 的确切代码,其中 Experiment::run() 函数作为单独的线程调用。

标签: c++ templates inheritance gcc c++11


【解决方案1】:

您的错误不在您显示给我们的代码中,您尝试在代码中绑定run 并使用std::thread 创建线程,这就是问题所在,因为它无法创建正确的struct 为您的绑定函数和最简单的解决方法是编写自己的包装器:

template< class Expr >
struct my_bind {
    my_bind( Expr& e, Notifiable& n ) : e_( e ), n_(n) {}
    void operator()() {e_.run(n_);}
    Expr& e_;
    Notifiable& n_;
};

然后使用你自己的包装器来启动函数,我不能肯定地说,但我认为这是编译器中的一个错误(所有编译器都有这个错误:GCC,MSVC,...),当你表达得到很复杂,他们无法在std::bind 中使用它!!

【讨论】:

  • 请在我的问题中查看更新的代码,但我认为您可能是对的,现在尝试一下。
【解决方案2】:

改变

 std::thread t(&Exp::run, e, *this);

std::thread t([](Exp&& e, Batch& b) { e.run(b); }, std::move(e), std::ref(*this));

或者如果你真的打算让线程从*this 继承一个副本:

std::thread t([](Exp&& e, Batch&& b) { e.run(b); }, std::move(e), *this);

错误的根源(至少是消息引用的那个)是特定 std::thread 构造函数的语义(我不打算在这里公开,它有点血腥)。如果您已经熟悉 std::bind 的语义(确实有自己的怪癖),您可以顺其自然:

std::thread t(std::bind(&Exp::run, std::move(e), std::ref(*this));

(再一次,std::ref(*this) 可以替换为 *this,这取决于你想要什么。)

【讨论】:

    猜你喜欢
    • 2015-01-01
    • 2018-11-22
    • 2021-09-26
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 2021-11-14
    • 1970-01-01
    • 2021-04-02
    相关资源
    最近更新 更多