2013-02-21 49 views
2

我与你分享了一个问题,我用类使用可变参数函数得到了一个问题。它是以下代码中显示的类Thread。它是std :: thread的一个包装,以便使用函数模式。C++多态性与可变参数函数

我想在继承Thread类进入一个新的类,仿函数使用多态性与这个功能,但是GCC返回错误吼叫:

#include <thread> 
#include <iostream> 

using namespace std; 

template<class... Args> 
class Thread 
{ 
public: 
    virtual void operator()(Args...) = 0; 

    void run(Args... args) 
    { 
    std::thread t(std::forward< Thread<Args...> >(*this), std::forward<Args>(args)...); 
    t.join(); 
    } 
}; 

template<class... Args> 
class Functor : public Thread<Args...> 
{ 
public: 
    // generates the errors bellow 
    virtual void operator()(Args... /*args*/) 
    { 
    } 

    // doesnot work since the pure virtual function wants another prototype of function. 
    // void operator()(int) 
    // { 
    // } 
}; 

int main() 
{ 
    int a = 12; 
    Functor<int> f; 
    f.run(ref(a)); 

    return 0; 
} 
 
from t-Thread-args2.cpp:1: 
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/tuple: In instantiation of ‘struct std::_Head_base, false>’: 
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/tuple:215:12: required from ‘struct std::_Tuple_impl, int>’ 
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/tuple:507:11: required from ‘class std::tuple, int>’ 
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/functional:1601:39: required from ‘struct std::_Bind_simple(int)>’ 
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/thread:133:9: required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = Thread; _Args = {int}]’ 
t-Thread-args2.cpp:14:83: required from ‘void Thread::run(Args ...) [with Args = {int}]’ 
t-Thread-args2.cpp:42:17: required from here 
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/tuple:166:13: error: cannot declare field ‘std::_Head_base, false>::_M_head_impl’ to be of abstract type ‘Thread’ 
t-Thread-args2.cpp:7:7: note: because the following virtual functions are pure within ‘Thread’: 
t-Thread-args2.cpp:10:18: note:  void Thread::operator()(Args ...) [with Args = {int}] 

我真的不理解,因为纯错误虚拟函数在派生类中被很好地定义。但是,在将函数run()移入派生类(Functor)中时,它起作用。

由于提前, 蚕儿

+0

“std :: forward”的用法没有意义。它对函数模板有意义,但是在你的代码中,run()不是函数模板。 – Nawaz 2013-02-21 07:51:01

+0

更具体地说,'std :: forward'在这里没有意义,因为它的参数总是'* this',即总是一个左值。 – jogojapan 2013-02-21 07:57:45

+0

@jogojapan:“std :: forward”的参数几乎总是左值,因为它通常有一个*名称*。 – Nawaz 2013-02-21 08:03:28

回答

2

按照[thread.thread.constr]§3中,std::thread构造函数的第一参数的类型是F&&,与FMoveConstructible是要求。在你的情况下,FThread,这不是MoveConstructible

换句话说,std::thread需要按值存储仿函数,并且将函数转发为Thread,这是抽象的。

+0

您的意思是我必须从MoveConstructible继承我的F类吗? – canercandan 2013-02-21 09:37:09

+0

@canercandan'MoveConstructible'是一个概念,而不是一个类。它意味着“可以使用移动构造函数构造类型的实例。”你的'Thread'是抽象的,所以它根本不能创建实例。你应该用实际的派生类类型来模拟'run()',或者(最好)使用'std :: ref',正如Mike在他的回答中所建议的那样。 – Angew 2013-02-21 09:40:26

1

的问题是:

std::forward< Thread<Args...> >(*this) 

它试图复制Thread子对象。幸运的是它是抽象的,所以你得到一个编译错误而不是意外的运行时行为。

你要参考包装来代替:

std::ref(*this) 
+0

非常感谢它! – canercandan 2013-02-21 09:36:18

1

我认为由参与者提供该主题包括使用std::ref的多个建议,愿与大家分享工作代码版本解决的问题,我用以前的代码得到。

#include <thread> 
#include <iostream> 

using namespace std; 

template<class... Args> 
class Thread 
{ 
public: 
    virtual void operator()(Args...) = 0; 

    void run(Args... args) 
    { 
    std::thread t(std::ref(*this), args...); 
    t.join(); 
    } 
}; 

template<class... Args> 
class Functor : public Thread<Args...> 
{ 
public: 
    void operator()(int) 
    { 
     while (1) 
      { 
      cout << "42 "; cout.flush(); 
      } 
    } 
}; 

int main() 
{ 
    int a = 12; 
    Functor<int> f; 
    f.run(ref(a)); 

    return 0; 
} 

再次感谢。

+0

请尝试充实你的答案多一点。只是在没有任何解释或上下文的情况下发布代码块并不好,对于未来寻找这个问题的答案的人可能没有任何价值。 – 2014-05-02 18:22:16

+0

@XaverKapeller刚刚编辑了更多解释的答案。 – canercandan 2014-10-11 15:34:04