Вопрос по c++, clone, c++11 – Делает ли Cll 11 decltype ненужным клон?

11

клон Paradigm используется для создания копии производного класса без приведения к типу базового класса. К несчастью,clone должен быть реализован в каждом подклассе (или с миксином с CRTP).

Есть ли шанс, что C ++ 11decltype делает это ненужным?

Я не думаю, что код ниже на самом деле копируетoriginal, но просто указывает на ссылку. Когда я пытался использоватьnew decltype(*original)Я получаю ошибку: error: new cannot be applied to a reference type.

Являетсяclone все еще путь в C ++ 11? Или есть какой-то новый способ использовать RTTI для копирования объекта производного класса из указателя базового класса?

<code>#include <iostream>

struct Base
{
  virtual void print()
  {
    std::cout << "Base" << std::endl;
  }
};

struct Derived : public Base
{
  int val;
  Derived() {val=0;}
  Derived(int val_param): val(val_param) {}
  virtual void print()
  {
    std::cout << "Derived " << val << std::endl;
  }
};

int main() {
  Base * original = new Derived(1);
  original->print();

  // copies by casting down to Base: you need to know the type of *original
  Base * unworking_copy = new Base(*original);
  unworking_copy->print();

  decltype(*original) on_stack = *original;
  on_stack.print();
  return 0;
}
</code>

Ваш Ответ

4   ответа
3

decltype не может и не восстанавливает динамический тип объекта. Это чисто статическая конструкция.

Нет волшебного способа скопировать объект. Вы должны вызвать конструктор с его окончательным динамическим типомsomewhere.

Я люблю твои 2 последних предложения! :)
3

decltype (как следует из названия) даетdeclared тип (статический тип) выражения, к которому он применяется.

decltype(*original) являетсяBase&поэтому ваш код будет распечатан

Derived 1
Base
Derived 1

но в третьем случае копия не будет сделана.

Клон (или какой-то другой вариант шаблона) по-прежнему остается в C ++ 11.

Вы можете использовать std :: decay, чтобы включить Base & amp; в базу.
2

RTTI to copy a derived class object from a base class pointer?

В случае, если кто-то заинтересован в неинвазивном клонировании, лямбды C ++ 11, по-видимому, предоставляют некоторые новые возможности клонирования. Размышляя о проблеме клонирования, я пришел к выводу, что тот, кто создал оригинальный экземпляр объекта, должен также быть тем, кто может помочь построить реплику. Рассмотрим случай, когда все ваши объекты изготовлены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 метод (связывая указатель на объект с лямбдой, которая будет вызывать конструктор копирования). Никогда не выбрасывайте старые чертежи, они могут понадобиться вам позже ;-)

Честно говоря, я все еще предпочитаю старыйclone решение с CRTP и т. д., но это может вызвать некоторые новые идеи или пригодиться в противном случае.

Код выше также наhttp://ideone.com/kIPFt2

EDIT: Как прокомментировал wjl, первая версия кода вызоветcloneFnMapнеуклонно расти. Подумав, я решил исправить код, добавив вshared_ptrвозвращается так, чтоcloneFnMap также будет очищен. Тем не менее, это следует рассматривать как экспериментальный код для проверки концепции.

Конечно, я просто старался сделать вещи как можно более минимальными.
Если бы кто-тоactually используйте эту технику, убедитесь, что создали shared_ptr с пользовательским средством удаления, которое удаляет указатель изcloneFnMap когда объект уничтожен, иначе он будет расти вечно.
21

decltype это статическая конструкция. Как и все конструкции типа C ++, он не может вывестиruntime тип объекта.decltype(*original) простоBase&.

@ AndrewTomazos-Fathomling: интересно, зачем использоватьstd::decay здесь, а неstd::remove_reference ?
@Mankarse Да, вот почемуonstack.print() использованияDerived::print, Но @ NicolBolas & apos; Смысл принятdecltype не может дать мне информацию о типе времени выполнения. user
Этот ответ (наряду с предыдущей версией моего ответа) опасно неправильный.decltype(*original) на самом делеBase&.
Вы можете использовать std :: decay, чтобы включить Base & amp; в базу.
@ AndrewTomazos-Fathomling +1 Полезно знать. user

Похожие вопросы