C ++ 11的decltype是否不需要克隆?

时间:2012-05-03 02:32:06

标签: c++ c++11 clone

clone范例用于制作派生类的副本,而不会转换为基类类型。不幸的是,clone必须在每个子类中实现(或者使用带有CRTP的mixin)。

C ++ 11 decltype是否有可能使这个不必要?

我不认为下面的代码实际上会复制original,而只是指向它的引用。当我尝试使用new decltype(*original)时,出现错误: error: new cannot be applied to a reference type

{+ 1}}仍然是C ++ 11的发展方向吗?或者是否有一些新方法使用RTTI从基类指针复制派生类对象?

clone

4 个答案:

答案 0 :(得分:21)

decltype是一个静态构造。与所有C ++类型构造一样,它不能推断出对象的运行时类型。 decltype(*original)只是Base&

答案 1 :(得分:3)

decltype(顾名思义)给出了应用它的表达式的声明的类型(静态类型)。

decltype(*original)Base&,因此您的代码将打印

Derived 1
Base
Derived 1

但在第三种情况下不会复制。

克隆(或模式的某些变体)仍然是C ++ 11中的方法。

答案 2 :(得分:3)

decltype无法恢复动态对象类型,也无法恢复。它是一个纯粹的静态构造。

复制对象没有神奇的方法。您必须调用其确切的最终动态类型某处的构造函数。

答案 3 :(得分:2)

  

克隆仍然是C ++ 11的发展方向吗?或者是否有一些新方法使用RTTI从基类指针复制派生类对象?

如果有人对非侵入式克隆感兴趣,C ++ 11的lambdas似乎提供了一些新的克隆设施:考虑克隆问题,我开始承认制造了一个对象的原始实例的人也应该是可以帮助构建副本的人。考虑所有对象都由某些Factory制造的情况。在这种情况下,除了通常的create界面外,您的工厂还可以配备clone界面,例如像这样:

#include <iostream>
#include <functional>
#include <memory>
#include <unordered_map>

template <typename BASE>
struct
Factory {
    private: using
    TCloneFn = std::function<std::shared_ptr<BASE>(BASE const * const)>;

    private:
    static std::unordered_map<BASE const*,TCloneFn> cloneFnMap;

    public: template <typename DERIVED_TYPE, typename...TS>
    static std::shared_ptr<BASE>
    create(TS...args) {
        BASE* obj = new DERIVED_TYPE(args...);
        const std::shared_ptr<BASE> pNewObj =
            std::shared_ptr<BASE>(
                obj,
                [&](BASE* p){
                    cloneFnMap.erase(p);
                    delete p;
                }
            );

        cloneFnMap[obj] = [&](BASE const * const orig){
            std::shared_ptr<BASE> pClone = create<DERIVED_TYPE>(std::ref(static_cast<DERIVED_TYPE const &>(*orig)));
            return pClone;
        };
        return pNewObj;
    }

    public: static std::shared_ptr<BASE>
    clone(std::shared_ptr<BASE const> original) {
        return cloneFnMap[original.get()](original.get());
    }
};

template <typename BASE> std::unordered_map<BASE const*,typename Factory<BASE>::TCloneFn> Factory<BASE>::cloneFnMap;

class Base {
    public: virtual ~Base() throw() {}
    public: virtual void whoAmI() const {
        std::cout << "I am Base instance " << this << "\n";
    }
};


class Derived : public Base {
    std::string name;
    public: Derived(std::string name) : name(name) {}
    public: Derived(const Derived&other) : name("copy of "+other.name) {
    }
    private: virtual void whoAmI() const {
        std::cout << "I am Derived instance " << this << " " << name << "\n";
    }
};

int main() {
    std::shared_ptr<Base> a = Factory<Base>::create<Derived>("Original");
    a->whoAmI();
    std::shared_ptr<Base> copy_of_a = Factory<Base>::clone(a);
    copy_of_a->whoAmI();
    std::shared_ptr<Base> copy_of_a_copy = Factory<Base>::clone(copy_of_a);
    copy_of_a_copy->whoAmI();
    return 0;
}

诀窍是要记住原始是如何在Factory::create方法中构造的(通过将指向对象的指针与将调用复制构造函数的lambda相关联)。永远不要丢弃旧蓝图,以后可能需要它们; - )

坦率地说,我仍然更喜欢使用CRTP等旧的clone解决方案,但这可能会引发一些新的想法或者其他方便使用。

上面的代码也在http://ideone.com/kIPFt2

编辑:正如wjl所评论的那样,代码的第一个版本会导致cloneFnMap稳步增长。在考虑完之后,我决定通过向返回的shared_ptr引入自定义删除器来修复代码,以便cloneFnMap也将被清除。不过,这应该只是一个实验性的概念证明代码。