【问题标题】:polymorphism with non-type template parameters具有非类型模板参数的多态性
【发布时间】:2012-07-13 20:14:40
【问题描述】:

我希望这不会过于复杂。我已经尝试在互联网上搜索了一段时间,虽然我发现了很多关于模板、继承等的 Q/As,但我找到的资源都没有处理这个特定问题:

我想为std::vector<T> 创建一个包装器,它只会创建std::vector<MyClass> 类型的向量或其任何继承的类。

这基本上看起来像:

Class Base;
Class Derived : Base;

template <Base T> class myVector{
public:
    void add(T);
protected: 
    std::vector<T> list;
}

目标是能够拥有一个具有以下行为的库:

Base       A;
Derived    D;
int        i;    

myVector<A> AVector;  // This should work
myVector<D> DVector;  // This should work
myVector<i> iVector;  // This should NOT work

AVector.add(A);  // This should work
AVector.add(D);  // This should work (through polymorphism)

DVector.add(D);  // This should work
DVector.add(A);  // This should not work

任何人都可以对上述问题/示例发表评论吗?我的最终目标是在 C++ 中推出我自己的基本事件处理。在这种情况下,A 将类似于 c# EventArgs。 B 将允许特定的 EventArgs 类型。我毫不怀疑 Boost 等人具有类似的功能,但我想暂时避开这条路线。

实际上,代码的工作方式类似于(在某种程度上基于我在互联网上某处找到的教程):

template<EventArgs arg> class Event{
    typedef void (*fptr)(arg);
    std::vector<fptr> listeners;
}


void notifylisteners(arg){
for (typename std::vector<fptr>::iterator iter = listeners.begin(); iter != listeners.end; ++iter)
    (**iter)(arg);  // there should be a check for a valid reference, in case one of the function pointers becomes invalid

声明

Event<myEventHandlerType> myEvent; 

与 C# 代码的功能相同:

public event myEventHandlerType myEvent;

由于依赖于 std::vector,此实现需要模板。在这里使用非类型参数模板(如果可以的话)的好处是它会强制使用特定的 eventArg 参数类型来传递给所有注册的处理程序,并且在编译期间错误会失败。

任何想法或cmets将不胜感激。

迈克尔

【问题讨论】:

标签: c++ events templates inheritance polymorphism


【解决方案1】:

如果您使用 C++11,您可以访问 std::is_base_of 和 static_assert()

你可以让编译器在传递 myVector 的类型不能转换为 Base 时给你一个错误。

#include <type_traits>

class Base
{};

class Derived : public Base
{};

template <class T>
class Foo
{
public:
    Foo()
    {
        static_assert (std::is_base_of<Base,T>::value, "Error: Type T not derived from Base");
    }
};

class Lol
{
};


Foo<Derived> foo1;
Foo<Lol> foo2; //Static assert fails

(在此处查看编译器输出http://ideone.com/NAXSA

如果您没有 C++11 支持,那么您需要做更多的工作,但仍然可以完成。看到这里关于https://stackoverflow.com/a/4532302/564944

【讨论】:

  • 我看不出有什么理由不使用 C++11 的特性。我在 Arch Linux 上使用 Intel 编译器(最新的)和/或 gcc(也是最新的)。这主要是为了我自己——便携性对我来说不是一个主要问题。
  • 无论如何,C++11 了!那个笔记主要是为了以防你是一个可怜的灵魂仍然坚持说 VS2008,这是我目前的工作案例。
【解决方案2】:

我希望我正确理解了您的描述。执行此操作的 C++ 方法不会通过继承,也不会“强制”传入从 A 继承的类型。相反,使用 duck typing:如果它看起来像鸭子,走路像鸭子,并且像鸭子一样叫,那么它就是鸭子,不管它的“官方”类型。

具体来说,myVector&lt;T&gt; 将简单地接受 any 类型 T。如果您尝试对不支持的T 对象执行某些操作,例如使用特定的arg 调用它,它将在编译时失败。

当然,记录T 需要支持的操作的签名是个好主意——本质上是它实现的接口。

(旁注:C++0x“概念”的概念可以让您在代码中表达这一点,但它已从标准中删除。)

【讨论】:

  • 这里的类型 T 实际上只是一个带有回调函数参数的包装类 - 即事件处理程序。 T 类确实没有任何硬性限制;这将更多地是一个一致性问题,尽管我可以预见到这个库的消费者可能会遇到问题。如果这成为问题,我从您的评论中了解到,我可以简单地创建某种否则会失败的依赖关系 - 可能通过声明将分配给 T 值的基类型的新指针。
猜你喜欢
  • 2012-12-26
  • 1970-01-01
  • 1970-01-01
  • 2023-01-25
  • 2018-05-15
  • 2014-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多