在派生类中使用关键字获取类型

时间:2015-03-16 06:14:41

标签: c++

考虑

struct AbstractClass {};

struct Derived1 : AbstractClass {
    using type = int;
};

struct Derived2 : AbstractClass {
    using type = char;
};

struct Derived3 : AbstractClass {
    using type = bool;
};

int main() {
    AbstractClass* a[] = {new Derived1, new Derived2, new Derived3};
}

如何从[0],[1],[2]获得type

这是我想要完成的事情。我想除此之外别无他法吗?

#include <iostream>

struct Object { virtual ~Object() = default; };
struct A : Object {};
struct B : Object {};
struct C : Object {};

struct AbstractClass {
    virtual void take (Object*) {
        std::cout << "Accepted.\n";
    }
};

template <typename...> struct ObjectTypes;

template <typename First, typename... Rest>
struct ObjectTypes<First, Rest...> : ObjectTypes<Rest...> {
    bool operator()(Object* o) const {
        if (dynamic_cast<First*>(o))
            return true;
        return ObjectTypes<Rest...>::operator()(o);
    }
};

template <>
struct ObjectTypes<> {
    bool operator()(Object*) const {return false;}
};

struct Derived1 : AbstractClass {
    using type = ObjectTypes<A,B>;
    virtual void take (Object* o) override {
        if (type()(o))  // This is why I want to use type from AbstractClass.
            return AbstractClass::take(o);
        std::cout << "Rejected.\n";
    }   
};

struct Derived2 : AbstractClass {
    using type = ObjectTypes<A,C>;
    virtual void take (Object* o) override {
        if (type()(o))
            return AbstractClass::take(o);
        std::cout << "Rejected.\n";
    }   
};

struct Derived3 : AbstractClass {
    using type = ObjectTypes<B,C>;
    virtual void take (Object* o) override {
        if (type()(o))
            return AbstractClass::take(o);
        std::cout << "Rejected.\n";
    }   
};

int main() {
    AbstractClass* abs[] = {new Derived1, new Derived2, new Derived3};
    A* a = new A;
    B* b = new B;
    C* c = new C;
    for (AbstractClass* x : abs) {
        x->take(a);
        x->take(b);
        x->take(c);
        std::cout << "------------\n";
    }
}

注意Derived1,Derived2,Derived3等中的重复...?因此,我最初的目标是在基类AbstractClass中完成所有工作。

2 个答案:

答案 0 :(得分:1)

解决方案受到Wojciech Frohmberg建议的启发,但我不确定这是他的意思。我实际上不知道他的意思,我认为他的意思是其他的,并希望看到他的解决方案,并找出他实际上在说什么。

#include <iostream>

struct Object { virtual ~Object() = default; };
struct A : Object {};
struct B : Object {};
struct C : Object {};

template <typename...> struct ObjectTypes;

template <typename First, typename... Rest>
struct ObjectTypes<First, Rest...> : ObjectTypes<Rest...> {
    bool operator()(Object* o) const {
        if (dynamic_cast<First*>(o))
            return true;
        return ObjectTypes<Rest...>::operator()(o);
    }
};

template <>
struct ObjectTypes<> {
    bool operator()(Object*) const {return false;}
};

struct AbstractClass {
    virtual void take (Object*) = 0;
    template <typename... Ts> void takeHelper (Object* o, ObjectTypes<Ts...>&& types) {
        if (types(o)) std::cout << "Accepted.\n";  // And now do whatever with o.
        else std::cout << "Rejected.\n";
    }
};

template <typename Derived>
struct AbstractClassCRTP : AbstractClass {
    virtual void take (Object* o) override {
        takeHelper(o, typename Derived::type{});
    }
};

struct Derived1 : AbstractClassCRTP<Derived1> {
    using type = ObjectTypes<A,B>;
};

struct Derived2 : AbstractClassCRTP<Derived2> {
    using type = ObjectTypes<A,C>;
};

struct Derived3 : AbstractClassCRTP<Derived3> {
    using type = ObjectTypes<B,C>;
};

int main() {
    AbstractClass* abs[] = {new Derived1, new Derived2, new Derived3};
    A* a = new A;
    B* b = new B;
    C* c = new C;
    for (AbstractClass* x : abs) {
        x->take(a);
        x->take(b);
        x->take(c);
        std::cout << "------------\n";
    }
}

输出:

Accepted.
Accepted.
Rejected.
------------
Accepted.
Rejected.
Accepted.
------------
Rejected.
Accepted.
Accepted.

答案 1 :(得分:1)

我更喜欢这样:

#include <iostream>

struct Object { virtual ~Object() = default; };
struct A : Object {};
struct B : Object {};
struct C : Object {};

struct SuperObjectType {
public:
    virtual bool operator()(Object *o) const = 0;
};

template <typename First, typename... Rest>
struct ObjectTypes: SuperObjectType {
    bool operator()(Object* o) const override {
        if (dynamic_cast<First*>(o))
            return true;
        return ObjectTypes<Rest...>()(o);
    }
};

template <typename OnlyOne>
struct ObjectTypes<OnlyOne>: SuperObjectType {
    bool operator()(Object* o) const override {
        return dynamic_cast<OnlyOne*>(o);
    }
};

struct AbstractClass {
    SuperObjectType *sot;
    void take (Object* o) {
        if ((*sot)(o)) {
            std::cout << "ACCEPTED" << std::endl;
        } else {
            std::cout << "REJECTED" << std::endl;
        }
    }
};
struct Derived1 : AbstractClass {
    Derived1()  {
        sot = new ObjectTypes<A,B>;
    }
};

struct Derived2 : AbstractClass {
    Derived2() {
        sot = new ObjectTypes<A,C>;
    }
};

struct Derived3 : AbstractClass {
    Derived3() {
        sot = new ObjectTypes<B,C>;
    }
};

int main() {
    AbstractClass* abs[] = {new Derived1, new Derived2, new Derived3};
    A* a = new A;
    B* b = new B;
    C* c = new C;
    for (AbstractClass* x : abs) {
        x->take(a);
        x->take(b);
        x->take(c);
        std::cout << "------------\n";
    }
}

但我很高兴我给你的灵感;)

(可能)加速表现的次要替代方案:

template <typename First, typename... Rest>
struct ObjectTypes: ObjectTypes<Rest...> {  // Derive from ObjectTypes<Rest...> instead.
    virtual bool operator()(Object* o) const override {
        if (dynamic_cast<First*>(o))
            return true;
        return ObjectTypes<Rest...>::operator()(o);
        // So now ObjectTypes<Rest...>::operator() can be used, and thus avoid instantiation.
    }
};

template <typename T>
struct ObjectTypes<T>: SuperObjectType {
    virtual bool operator()(Object* o) const override {
        return dynamic_cast<T*>(o);
    }
};

因为ObjectTypes<T>是从任何类型T的SuperObjectType派生的,所以ObjectTypes<First, Rest...>也是从SuperObjectType派生的(通过派生自ObjectTypes<Last>,Last是Rest中的最后一个类型。 ..)。所以一切仍然有效(经过测试)。