Переинициализировать с помощью делегирующего конструктора

У меня есть этот класс X, используя делегирующий конструктор, я хочу изменить только значение i а также j как 0. Можно ли это сделать?

class X{
public:
    X() = default; 
    X(int ival, int jval) : i{ ival }, j{ jval } {} 
    X(int new_i) : i{ new_i }, X(i, 0) {}    //error here


private:
    int i; 
    int j; 
};

int main()
{
    X x{ 345, 54 };

    x = X{ 34 };  //annoymous copy changes only the i:member
    return 0; 
}

РЕДАКТИРОВАТЬ: я знаю X(int new_int) : X{new_int, 0} будет работать, но я хотел знать, в чем ошибка, если инициализировать еще одну переменную в списке.

Может быть у меня есть другой z и я хочу инициализировать это вместе с i а также j,

т.е. X(int new_i) :z{ new_i }, X(new_i, 0) {}

3 ответа

Решение

Просто используйте

X(int new_i) :  X(new_i, 0) {}

Из проекта стандарта C++ N3337 (выделено мной):

12.6.2 Инициализация баз и членов

6 А mem-initializer-list может делегировать другому конструктору класса конструктора, используя любой class-or-decltype это обозначает сам класс конструктора. Если mem-initializer-id обозначает класс конструктора, он должен быть единственным mem-initializer ;

Почему бы тебе не сделать это?

X(int new_i) :X(new_i, 0){...}

Таким образом, вы будете устанавливать j-го значения до 0, и имеют только x переменная.

В списке инициализаторов не может быть делегирующего конструктора и другого инициализатора члена. Это недопустимо, поскольку порядок инициализации не может быть порядком объявления члена, вместо этого некоторые переменные будут инициализированы дважды, что потенциально плохо определено.

Если ваш пример был разрешен, то рассматриваемый конструктор сначала инициализируется i<- new_i, затем i<- i, затем j<- 0, С неconstintэто может быть осуществимо, но не с более общими типами.


Просто инициализируйте объекты через делегирование:

class X
{
public:
  X() = default; 
  X(int ival, int jval) : i{ival}, j{jval} {} 
  X(int ival) : X(ival, 0) {}    
private:
  int i; 
  int j; 
};

Хотя в этом случае лучше использовать аргументы по умолчанию:

class X
{
public:
  X() = default; 
  X(int ival, int jval=0) : i{ival}, j{jval} {} 
private:
  int i; 
  int j; 
};

Вы также должны рассмотреть возможность использования explicit ключевое слово для конструкторов с одним аргументом, чтобы избежать неприятных сюрпризов... как в

void foo(X);
foo(1);       // calls foo(X(1));
Другие вопросы по тегам