3

我正在与您分享一个使用可变参数函数参数的类所遇到的问题。它是下面代码中显示的类 Thread。它是 std::thread 的包装器,以便使用函数模式。

我想在这个函数中使用多态性将类 Thread 继承到一个新类 Functor 中,但是 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;
}
从 t-Thread-args2.cpp:1:
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/tuple:在'struct std::_Head_base的实例化中, 假>':
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/tuple:215:12:来自'struct std ::_Tuple_impl, int>'
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/tuple:507:11:来自'class std ::元组,整数>'
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/functional:1601:39:来自'struct std ::_Bind_simple(int)>'
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/thread:133:9: 来自'std: :thread::thread(_Callable&&, _Args&& ...) [with _Callable = Thread; _Args = {int}]'
t-Thread-args2.cpp:14:83: 需要来自 'void Thread::run(Args ...) [with Args = {int}]'
t-Thread-args2.cpp:42:17:从这里需要
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/tuple:166:13:错误:无法声明字段'std::_Head_base, false>::_M_head_impl' 为抽象类型'Thread'
t-Thread-args2.cpp:7:7: 注意:因为以下虚函数在“线程”中是纯的:
t-Thread-args2.cpp:10:18: 注意: void Thread::operator()(Args ...) [with Args = {int}]

我真的不明白这个错误,因为纯虚函数在派生类中定义得很好。但是,将函数 run() 移动到派生类 (Functor) 中,它可以工作。

在此先感谢, Caner

4

3 回答 3

2

根据 [thread.thread.constr]§3,std::thread构造函数的第一个参数的类型是F&&,要求FMoveConstructible。在您的情况下,FThread,不是MoveConstructible

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

于 2013-02-21T07:48:56.697 回答
2

问题是:

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

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

您需要一个参考包装器:

std::ref(*this)
于 2013-02-21T07:53:03.613 回答
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;
}

再次感谢。

于 2013-02-21T09:39:05.317 回答