В чем причина невозможности определить размер массива из строки инициализатора в переменной-члене?

Рассмотрим код:

struct Foo
{
const char str[] = "test";
};

int main()
{
Foo foo;
}

Он не компилируется как с g ++, так и clang ++, выпуская по существу

error: array bound cannot be deduced from an in-class initializer

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

15

Решение

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

struct Foo
{
Foo() {} // str = "test\0";

// Implementing this is easier if I can clearly see how big `str` is,
Foo() : str({'a','b', 'c', 'd'}) {} // str = "abcd0"const char str[] = "test";
};

Обратите внимание, что замена const char с static constexpr char работает отлично, и, вероятно, это то, что вы хотите в любом случае.

11

Другие решения

Если компилятору было разрешено поддерживать то, что вы описали, и размер str был выведен 5,

Foo foo = {{"This is not a test"}};

приведет к неопределенному поведению.

2

Как упомянуто в комментариях и как ответил @sbabbi, ответ заключается в деталях

12.6.2 Инициализация баз и членов [class.base.init]

  1. В не делегирующем конструкторе, если данный нестатический элемент данных или
    базовый класс не обозначается идентификатором mem-initializer-id (включая
    случай, когда нет mem-initializer-list, потому что конструктор
    не имеет инициализатора ctor), и объект не является виртуальным базовым классом
    абстрактный класс (10.4), тогда

    • если объект является нестатическим элементом данных, который имеет инициализатор с фигурной или равной скобкой, объект инициализируется, как указано в
      8,5;
    • в противном случае, если объект является анонимным объединением или вариантом члена (9.5), инициализация не выполняется;
    • в противном случае объект инициализируется по умолчанию

12.6.2 Инициализация баз и членов [class.base.init]

  1. Если данный нестатический элемент данных имеет
    инициализатор скобок или равных и инициализатор mem, инициализация
    заданный mem-инициализатор выполняется, и нестатические данные
    инициализация-член-скобка игнорируется. [Пример: дано

    struct A {
    int i = /∗ some integer expression with side effects ∗/ ;
    A(int arg) : i(arg) { }
    // ...
    };
    

конструктор A (int) просто инициализирует i значением arg,
и побочные эффекты в I Brace- или Equal-Initializer не будут принимать
место. — конец примера]

Таким образом, если существует не удаляющий конструктор, инициализатор фигурных скобок игнорируется, и инициализация внутри элемента конструктора преобладает. Таким образом, для элементов массива, размер которых опущен, выражение становится некорректным. §12.6.2, пункт 9, делает это более явным, когда мы указали, что выражение инициализатора r-значения опущено, если mem-initialization выполняется конструктором.

Кроме того, обсуждение группы Google Еще одно несоответствующее поведение в C ++, дорабатывает и делает его более ясным. Это расширяет идею объяснения, что инициализация-скобка или равный-инициализатор является прославленным способом инициализации в элементе для случаев, когда инициализация в элементе для элемента не существует. В качестве примера

struct Foo {
int i[5] ={1,2,3,4,5};
int j;
Foo(): j(0) {};
}

эквивалентно

struct Foo {
int i[5];
int j;
Foo(): j(0), i{1,2,3,4,5} {};
}

но теперь мы видим, что если бы размер массива был опущен, выражение было бы неправильно сформировано.

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

2
По вопросам рекламы [email protected]