【问题标题】:Operating with template objects使用模板对象进行操作
【发布时间】:2012-08-28 11:19:10
【问题描述】:

免责声明我不允许使用 BOOST 或任何其他库,只能使用标准库。

在我的班级Foo 我有一个模板函数foo,它有两个参数:一个pointer-to-object 和一个pointer-to-this-object-成员函数。如您所见,foo 函数适用于任何类的指针。我不知道,什么类将传递给它。该函数创建一个模板结构的实例。

template <typename TypeName>
struct Bar
{
    void(TypeName::*action)();
    TypeName* objPtr;
};



template <typename TypeName> void Foo::foo ( void(TypeName::*action)() , TypeName* objPtr )
{
    Bar <TypeName> bar;
    bar.action = action;
    bar.objPtr = objPtr;
};

我的问题是:如何存储foo 中创建的Bar 的对象,以便稍后遍历它们并调用pointer-to-an-object-member-function 像这样:

(BarStorage[i].objPtr->*BarStorage[i].action)();

【问题讨论】:

  • pointer-to-an-object-member-function 本质上是一个 delegate。也许它会帮助你。
  • 你甚至不允许使用标准库,在 C++11 中对 function objects and binding 有很好的支持?
  • 你不能存储Bar的实例,因为Bar是一个类模板,所以你不能创建它的实例。
  • 只允许使用标准,包括 C++11。
  • 所以std::functionstd::bind 应该足够了。

标签: c++ templates pointers function-pointers pointer-to-member


【解决方案1】:

使用类型擦除

class BarBase {
    virtual void invoke() = 0;
};

template<typename TypeName>
class Bar final : public BarBase {
    void(TypeName::*action)();
    TypeName* objPtr;
    virtual void invoke() override { (objPtr->*action)(); }
};

class Foo {
    std::vector<std::unique_ptr<BarBase>> myBars;
/* ... */
};

template <typename TypeName>
void Foo::foo ( void(TypeName::*action)() , TypeName* objPtr)
{
    auto bar = new Bar<TypeName>();
    bar->action = action;
    bar->objPtr = objPtr;
    myBars.emplace_back(bar);
};

然后只需拨打myBars[x]-&gt;invoke();


在 cmets 中回答问题。

override 是怎么回事? 明确地说您从基类重写了虚函数。这在这里并不是真正必要的,但被认为是良好的做法。更多详情请见Wikipedia article

它是 C++11 的一个新特性,一些编译器在很长一段时间内都以某种方式支持这个特性,但直到现在它才被标准化。 GCC should support this feature from version 4.7 - 你必须使用命令行参数-std=c++0x

unique_ptr 怎么样了? 它让生活更轻松。当您分配new Bar&lt;XXX&gt;() 时,您必须在某些时候说delete 以释放该内存。如果你把指针放在像unique_ptr 这样的资源管理对象中,你就不再需要担心删除它了。使用vector&lt;BarBase*&gt;,您必须在Foo 中声明一个析构函数,其作用类似于:

for each element in myBars
    delete element

如果您使用vector&lt;unique_ptr&lt;BarBase&gt;&gt;,则无需担心删除任何内容。当vectorFoo 的生命结束时被销毁时,它会销毁它的元素 - 而unique_ptr 会删除它包含在自己的析构函数中的内存。

这也是 C++11 的特性 - 标准库的补充。您不必使用它(但请确保最后删除所有内容)。

auto 是怎么回事? 不要重复两次相同的类型(Bar&lt;Type&gt; * bar = new Bar&lt;Type&gt;();),只需使用一次,然后让编译器根据类型推断出变量的正确类型初始化器。它的行为完全相同,只是打字更少,看起来更好:)

还有 C++11 功能,自 v4.4 起在 GCC 中受支持。

为什么myBars[x]-&gt;invoke() 做正确的事?因为invokeBarBase 中被声明为虚拟。这意味着执行的方法是根据myBars[x] 的动态类型(执行期间的真实类型)而不是静态类型来选择的。更深入的解释见Wiki。这种机制的运行时开销很小,但在处理动态类型时无济于事。

【讨论】:

  • 伙计,这是一个 AWESOME 的想法。要试试这个!非常感谢。
  • @Fiktik,我可以问你一些关于你的代码的问题吗?我的编译器 g++ 不知道 override 关键字的这种语法。是新标准还是什么?我只需输入virtual void invoke() { (objPtr-&gt;*action)(); }。第二:你为什么用unique_ptr,而不仅仅是vector&lt;BarBase*&gt; myBars;。三、auto是什么?新标准中的一些新功能?我只需输入Bar&lt;TypeName&gt;* bar = new Bar &lt;TypeName&gt; ( );
  • 还有主要问题:为什么myBars[x]-&gt;invoke(); 调用覆盖函数而不是基函数? myBars 存储指向BarBases 的指针,那么为什么不调用基函数呢?
  • @Kolyunya 我已经在答案中添加了解释。
  • @Fiktik,感谢您的帮助,也许您会在这里找一分钟来看看问题的延续? stackoverflow.com/questions/12178280/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-04
  • 2020-03-22
  • 1970-01-01
  • 1970-01-01
  • 2012-08-27
  • 2019-03-08
相关资源
最近更新 更多