【问题标题】:Curiously recurring template pattern with ptrhead带有 ptrhead 的奇怪重复模板模式
【发布时间】:2014-08-27 02:05:20
【问题描述】:

所以我想弄清楚你是否可以使用奇怪的重复模板模式来绕过 pthread 与类方法一起使用的限制,甚至通过做一些类似的事情来创建类。

template <class T>
class thread_helper
{
  static void* create(void *input)
  {
     T * output=new T;
     return static_cast<void*>(output);
  }

  static void* using(void *input)
  {
    T::use(input);
  }
};

class user : public thread_helper<user>
{
  void method(int x)
  {
    //does something
  }
  static void use(void* input)
  {
    this->method(static_cast<int>(input));
  }
};

然后你可以使用 pthread 来调用类创建使用

pthread_create(thread_variable, NULL, thread_helper::create<some_class>, void);

和另一个电话

pthread_create(thread_variable, NULL, user::using(), void);

注意:上面的代码有很多错误。请不要为了他们撕毁我。我真的只是想描绘我正在尝试做的事情。我也在尝试找出是否有更好的方法来执行此操作。

另外,第二个pthread_create 方法真的很有必要,我不能只使用构造函数吗?

【问题讨论】:

  • using 是保留字。无论如何,典型的范例是将您的类实例地址转换为 void* 并将其作为线程参数传递给线程过程,该线程过程将其转换回相同的指针。如果您有 C++11,请考虑使用 std::thread。
  • "如果有更好的方法来执行这个操作" - 在单独的线程中运行构造函数通常不是很有用,除非你有一些同步的方式来访问对象 - 我建议你阅读在std::future 等人上。
  • @TonyD 我检查了 std::future。这让我很恼火,我不能在这个项目中使用新标准。我也同意你不确定构造函数部分是否真的需要线程化。无论如何,我最终得到了一个代码,它可以工作,但它有大量的样板代码。

标签: c++ templates crtp


【解决方案1】:

我将发布一个有效的测试代码。它涉及大量的样板代码。它真的很难看,但有效。注意:我可能会在以后更改 thread_helper 的 create 方法,因此它不能用于线程。

#include <iostream>
#include "pthread.h"

using namespace std;

template <class I>
struct helper
{
    void *(I::*method)(void *); //enables you to call and get information from any non static class method
    I *ptr; //this is the class pointer used to call the member pointer
    void *info; //this is what you pass into the member pointer
};

template <class T>
class thread_helper
{
public:
    static void *create(void *in)
    {
        T * output=new T;
        return static_cast<void*>(output);
    }

    static void *method(void *in)
    {
        helper<T> *utilize = static_cast<helper<T> *>(in);
        return (utilize->ptr->*utilize->method)(utilize->info);
    }
};

class test: public thread_helper<test>
{
public:
    void *test_method(void *in)
    {
        int *val = (int *)in;//note: not static_casting since this is not a class
        *val *= 4;
        return val; //auto casts to void *
    }
};

int main()
{
    //initialize test
    test * second = static_cast<test*>(test::create(NULL));

    //initialize helper
    helper<test> first;
    first.ptr = second;
    first.method = &test::test_method;
    int val = 4;
    first.info = &val;//

    //setup threads
    pthread_t thread;
    void *ans;

    //call test_method and retrieve answer
    pthread_create(&thread, NULL, test::method, static_cast<void *>(&first));
    pthread_join(thread, &ans);

    cout << "the answer is "<< *(int *)ans <<endl;
    return 0;
}

正如所指出的,如果您使用的是 pthread,则此解决方案有效。并且是编写函数或静态方法来调用类的方法的通用替代品。

如果您使用的是 boost 或 c++11 线程,则不需要并且可能不应该使用此方法,因为它需要大量样板代码(指针转换)。

【讨论】:

  • 你可以使用reinterpret_cast代替C-cast。
  • @Jarod42 reinterpret_cast 不危险吗?
  • C-Cast is 更危险,因为它不明确。 reinterpret_cast 是明确的(但仍然很危险)。