Базовый конструктор CRTP падает, потому что дочерний элемент не создан - PullRequest
0 голосов
/ 30 ноября 2018

У меня есть классы, которые генерируются автоматически, но я хочу, чтобы конечные пользователи могли добавлять пользовательские функции-члены и конструкторы.

Мой подход заключается в использовании базового класса CRTP, в котором нет переменных-членов, а только функции.

Проблема заключается в конструкторе.Если я определяю конструктор в своем CRTP, я не могу правильно получить доступ к дочернему элементу, поскольку он еще не создан, поскольку конструктор дочерних классов вызывается только после построения базы CRTP.

#include <iostream>
#include <string>

template<class Child>
struct Foo {
  Foo(std::string i) {
    // Childs constructor is not run yet.
    std::cout << static_cast<Child&>(*this).d.size(); // Prints trash
    static_cast<Child&>(*this).d = i; // Segfault here
    (void) i;
  }
};

// Cannot change this class.
struct Bar : Foo<Bar> {
  using base_t = Foo<Bar>;
  using base_t::base_t;
  std::string d;
};


int main()
{
  Bar bar("asdgasdgsag");
  std::cout << "bar.d: " << bar.d << std::endl;
}

Есть ли способ решитьэта проблема?

Ответы [ 2 ]

0 голосов
/ 01 декабря 2018

Есть решение.Это не UB в соответствии со стандартом C ++ 17, а UB для C ++ 14.Он также не является чистым.

#include <iostream>
#include <string>

#if __cpp_inheriting_constructors < 201511
  #error "Not supported."
#endif

template<class Child>
struct post_construct{
    Child* constructed;
    std::string i;
    ~post_construct(){
        constructed->d=std::move(i);
    }
};


template<class Child>
struct Foo {
  Foo(std::string i,post_construct<Child>&& m=post_construct<Child>{}) {
    m.constructed = static_cast<Child*>(this);
    m.i = std::move(i);
  }
};

// Cannot change this class.
struct Bar : Foo<Bar> {
  using base_t = Foo<Bar>;
  using base_t::base_t;
  std::string d;
};


int main()
{
  Bar bar("asdgasdgsag"); //temporary materialization here
                          //then temporary destroyed at end of full-expression
  std::cout << "bar.d: " << bar.d << std::endl;
}

Демоверсия

Код сборки и проверки компилятора

0 голосов
/ 30 ноября 2018

Ваш базовый конструктор не может ничего сделать с дочерним классом.Совсем.Последнее еще не было построено.

CRTP позволяет другим функциям-членам Foo делать это, но это все.

В дизайне, к которому вы пришли, "быстрого исправления" нетмы придумали.Вы можете либо добавить Init -подобную функцию к Foo, чтобы сделать это позже (и вызвать ее из ctor-объекта ребенка), либо (в идеале) переосмыслить свой подход.

Это немного странно, что выне может изменить дочерний класс, но добавляет вещи в Base - это не то, как предполагается наследование, и кажется, что вы пытаетесь использовать CRTP, чтобы разобраться с этим, но выяснили, почему этоне действительный взлом.

Не зная, что вы пытаетесь сделать, я не могу быть более точным, чем это.

Может быть, заводская функция может вам помочь?Или наследовать от Bar.

...