Как определить некоторые конструкторы только для неконстантных объектов? - PullRequest
0 голосов
/ 04 сентября 2018

Имея следующий класс:

class Foo {
public:
  Foo() : m_data{std::nullopt} {} // this is fine (not having m_data set), 
                                  // but only at the beginnig of objects lifetime
  Foo(Bar data) : m_data{data} {}

  void setData(Bar newData);
  Bar getData() const;

  void doJob() const; // requires m_data to be set (not std::nullopt)
  void doOtherJob() const; // does not require m_data to be set.
  /*...*/

private:
  std::optional<Bar> m_data;

В начале, есть вероятность, что m_data не будет установлен, но только до точки первого setData() вызова, тогда m_data никогда не вернется к тому, чтобы быть пустым (std::nullopt)

Мой вопрос: могу ли я как-то сказать компилятору никогда не разрешать конструирование объектов типа Foo с первым конструктором (по умолчанию: Foo()), если эти объекты помечены как const так что не будет шансов для этого типа кода:

const Foo x;           // without const totally fine
// x.setData( Bar{} ); // but with it, setData cannot be called
x.doJob();             // which makes that call a 100% throw error
                       // and in general, whole object is less usefull now
                       // because it is constructed only partially, 
                       // and cannot be finished 

пройти этап компиляции?

Конечный эффект должен выглядеть так:

Bar data = getSomeData();

Foo a;             // fine
Foo b{data};       // fine
const Foo c;       // error, this type will never be usefull / is artificially limited, 
                   // no logical reason to make it const
const Foo d{data}; // fine

Есть ли способ получить во время компиляции информацию о const'ness данного нового объекта (в строительном коде или определении класса объектов), чтобы я мог использовать SFINAE или что-то еще для разделения, различения различных процедур построения для const и not-const объекты?

Я хочу, чтобы это было сделано во время компиляции.

Было бы неплохо иметь возможность написать что-то вроде:

class Foo{
public:
                                    // both can still mutate everything
  Foo() { /*...*/ }                 // but this one cant be called by const objects            
  Foo(Bar data) const { /*...*/ }   // and this one can
};

, который не будет пытаться сделать this указатель const Foo*, а только притворяется, как это, поэтому объекты const не могут вызвать этот первый "метод", но это не разрешено тем, что я знаю и проверено на это точка.

(тип Bar не может быть установлен на какое-либо значение по умолчанию, нулевое значение. Оно либо есть, либо нет, и я бы хотел оставить его таким)

Я также не знаю, почему нельзя пометить конструкторы const, потому что тогда (по моему мнению) не было бы проблем со всеми теми классами, где объекты могут быть построены частично, но после все равно придется быть полностью выполненным, чтобы работать должным образом или работать в своем потенциале.

Я не смог найти другого программиста с такой же проблемой, поэтому я привел расширенный пример кода, чтобы проверить, действительно ли это проблема (с другим подходом для создания const объектов) или я просто делаю что-то неправильно путь. Есть ли какой-то шаблон дизайна, стиль программирования и т. Д., Который мне не хватает и который делает эти проблемы не существующими?

Я знаю, что на run-time нет никакой разницы между const и not-const объектами, но это не главное. Я считаю, что эту проблему можно решить на compile-time, я просто не знаю, как сказать компилятору, что я имею в виду.

Редактировать : Создание объекта с Foo() полезно (используя только часть его функциональных возможностей), но только если позже оно выполнит свою основную работу, которая требует m_data.

1 Ответ

0 голосов
/ 04 сентября 2018

Нет, в конструкторе невозможно узнать, будет ли объект постоянным или неконстантным. Таким образом, желаемую функциональность невозможно реализовать. У вас есть два варианта:

  • Удалить конструктор по умолчанию. Если doJob является ошибкой для построенного объекта по умолчанию, то почему бы не запретить такое недопустимое состояние?
  • Примите тот факт, что const Foo c; бесполезен, но компилятор не скажет программисту. Программист должен выяснить это довольно скоро, если они проверят код, который они пишут. Бесполезность также должна стать совершенно ясной из документации класса.
...