【问题标题】:C++ store template parameter as variableC++ 将模板参数存储为变量
【发布时间】:2012-01-16 20:31:38
【问题描述】:

我正在为我们在其他代码中定义的一堆类编写一个通用包装类。我试图弄清楚 C++ 中是否有一种方法可以编写一个可以将模板参数存储为变量的模板类。这是我希望看到的工作示例:

template < class C > class generic {
    public:
        C obj; // used for custom type processing

        template < class T > T other; // <- changeable variable (or something)

        template < class T > setOther() { // Function to change variable
            // code to change variable type, or set type
        }

        void doSomethingWithOther() {
            // do some processing for other, like call
            // specific member function or something
            (((other*)obj)->*SomeGenericMethod)()
        }
}

int main(int argc, char **argv) {
    Bar bObj;
    generic<Foo> fObj;
    fObj.setOther<Bar>();
    fObj.doSomethingWithOther();
    return 0;
}

我知道上面的代码由于很多原因无法编译,但我的问题更多是关于功能。有什么方法可以将模板参数存储为变量(或使用函数或其他东西),然后可以稍后用作类型说明符?如果没有标准方法,来自 SO 社区的任何想法可能会导致我想要的结果?

请不要使用 Boost 或其他 3rd 方库,我正尽量将其保持为“STL”(C99)。

我的另一个想法是使用默认特化:

template < class C, class T = void* > class generic {
    public:
        C obj;
        T other;
        // ... more code
}

但在那种情况下,假设我们有以下情况:

class Test1 {
    public:
        generic<Foo> *G1;
        generic<Foo, Bar> *G2;
};

如果我以后想改变 G1 的类型来做一些其他的处理,我可以这样说:

G1 = new generic<Foo, Bar>(); // compile error, different types

但是,这会导致编译错误,因为指向的两种类型属于不同类型(G1 的类型为 generic&lt; C &gt;,另一个类型为 generic&lt; C, T &gt;,即使模板类 T 默认为 @987654328 @。

抱歉,这篇文章太长了,我试图用这段代码尽可能清楚地表达我的意图。另外,请随时纠正我在上面的任何陈述(长时间=我的大脑活动较少)

提前感谢您在此问题上的任何帮助。

编辑 1:

澄清一下,other 数据成员只是为了表明我希望该成员拥有一个类类型。这是因为我们的代码有其他类的成员调用实例化的成员函数。如果我要调用另一个类的成员函数,我会得到一个编译错误。

不幸的是,我无法使用任何 C++0x 功能,因为我们的嵌入式编译器较旧且不支持 0x 功能集。否则这将是显而易见的解决方案。

我本质上必须构建一个委托类型的系统,以便实例类可以从自身内部调用其他实例类的成员,并且被调用的成员函数将拥有内存空间并可以访问 this 指针

例子:

class Foo {
    public:
        Delegate other;
}

class Bar {
    public:
        void SomeFunction() {
            std::cout << "hello from Bar::SomeFunction, data = " << data << std::endl;
        }

        int data;
}

int main() {
     Foo F;
     Bar B;
     B.data = 10;
     F.other = Delegate::attach<Bar>(&Bar::SomeFunction, &B);
     // Delegate::attach is defined as 
     // template < class T > Delegate attach(void (T::*fnPtr)(void*), T *obj)
     F.other();
}

在上面的示例中,Delegate 类的void operator()() 然后通过(*fnPtr)() 调用其他成员函数。如果以这种方式调用,该函数将无法访问其成员数据(不知道this 指针)。如果调用传递引用的对象(即(*fnPtr)(obj)),该函数现在可以访问成员数据。

我正在尝试通过指定一个通用的 class type 对象来解决这个问题,然后该对象可以来回转换,因为 Delegate other 可以附加到任何成员。

【问题讨论】:

  • other 依赖什么来确定它是什么?
  • ¤ “请不要 Boost 或其他 3rd 方库”是弄巧成拙的。你不想再重新发明那个轮子,所以使用 boost::any 或 boost::variant (我忘了哪个是哪个)。或者使用该源代码作为起点,尽管您不太可能对其进行改进:使其不提升的修改只会降低质量。无论如何,你到底为什么想要这个?看起来确实您是在询问某个问题的设想解决方案,而不是询问那个问题。如果是这样,请询问问题。干杯&hth.,
  • “尽可能保持 STL”(我假设您的意思是 C++ 标准库):您知道标准受 Boost 及其作者的影响吗?
  • @pmr 这不是设计标准库或影响它的人,而是您必须重新分发(或希望收件人已经拥有)大型 boost 库 - 在学习并成功编译它之后,等等,对于某些人(包括我自己)来说,痛苦太多,收获却不够。
  • @Seth,我同意可移植性,这就是我试图避开第 3 方库的原因。虽然我不是想重新发明轮子,但公司要求我们的代码库尽可能地便携。它是我们一些嵌入式产品的通用 SDK,不幸的是,由于我们需要在一些平台上工作(奇怪的编译环境),因此需要大量的“重新发明轮子”。

标签: c++ class templates generics


【解决方案1】:

尚不清楚您要解决的问题是什么。在您的代码中,class C 的用途是什么?无论如何,这是您想要的猜测。使用从具有虚拟interface 的公共基类派生的底层模板类implementation,并让generic 类持有指向该interface 的指针。

class generic {
    class interface {
    public:
        virtual ~interface(){}
        virtual void SomeGenericMethod()=0;
    };
    template <class T>
    class implementation: public interface {
        T data;
    public:
        implementation(const T& d) :data(d) {}
        virtual void SomeGenericMethod() 
        {return data.SomeGenericMethod();}
    };
    public:
        std::unique_ptr<interface> data;

        template < class T > void setOther(const T& other) {
            data.reset(new implementation<T>(other));
        }

        void doSomethingWithOther() {
            data->SomeGenericMethod();
        }
};

int main(int argc, char **argv) {
    generic fObj;
    Bar bObj;
    fObj.setOther(bObj);
    fObj.doSomethingWithOther();
    return 0;
}

http://ideone.com/A1Aqu

【讨论】:

  • 嗨,class C 是我现在使用的代码中签名的一部分,它用于泛型类的其他部分,对问题的结果并不重要,很抱歉没有澄清这一点。无论如何,感谢您的回复和提示,我会尝试您的建议的变体,因为我认为它可能会让我走上正确的轨道
  • 好消息是我刚刚被告知我现在可以实现 C++0x,并且虚拟接口技巧最终实现了我想要做的目标......谢谢!
  • @txtechhelp:很高兴我能帮上忙! unique_ptr 不是答案的关键,它只是防止错误。
  • @txtechhelp:另外请注意,如果相关对象从通用虚拟接口派生而来,这一切明显更容易。
  • 同意 unique_ptr,它非常方便,它确实让我的生活更轻松,另外,我选择这个答案的主要原因是因为我们将传递的所有对象实际上都是派生自我们用于许多数据类型的纯虚拟“接口”类。再次感谢您的帮助!
【解决方案2】:

如果您在编译时不知道确切的类型,则无法将其编码为模板参数。这些必须在编译时就知道,之后就不能更改了。查看Boost.Any(任何可能的类型)或Boost.Variant(多种已知类型)以获取可以帮助您的示例。 any 可以通过合理的努力实现,variant 则不然。鉴于您对 C++ 模板的了解,您可能不应该在没有真正理解 boost 中的代码的情况下尝试实现任何一种,无意冒犯。

【讨论】:

  • 感谢您的信息,我将研究 Boost 库如何实现其变体类型,看看它们是否可以提供帮助。不幸的是,由于严格的编码执行,我不能使用任何 3rd 方库,否则这一切都没有实际意义,哈哈。
  • 但请不要尝试自己实现。
【解决方案3】:

听起来你的主要目标是调用other的一些成员函数。

如果是这样的话,你甚至不需要other,而只需要一个封装调用的函子。例如。使用 C++11 或 TR1:

template <class C> struct A {
    C obj;
    std::function<void ()> op;
    void f() {
        // ...
        op();
    }
};

struct B {
    void g() { std::cout << "moo" << std::endl; }
};

int main() {
    A<int> a;
    B b;
    a.op = std::bind(&B::g, &b);
    a.f();
}

【讨论】:

  • 嗨 Georg,感谢您提供的信息,不幸的是,我无法使用任何对我当前情况有帮助的 C++0x 功能(不支持编译器)。虽然我确实喜欢这个想法,因为它很简单,但我基本上想在我的代码中模拟这个功能,回到 Google ..
  • @txt: 也许看看fast delegates 或使用bcp 提取boost::functionboost::bind
猜你喜欢
  • 2013-10-13
  • 2014-06-20
  • 1970-01-01
  • 2019-03-29
  • 2013-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多