Почему этот список инициализаторов конструктора, который инициализирует компиляцию C-массива?

Я сам очень редко использую C-массивы, но я придумал следующий фрагмент кода, пытаясь ответить на чей-то вопрос:

#include <cstddef>

template <std::size_t n>
class A {
public:
  explicit A(const int (&arr) [n]) : arr_(arr) {  }

private:
  const int arr_ [n];
};

int main(int, char**) {
  const int arr [3] = { 1, 2, 3 };
  A<3> a (arr); // (1)

  return 0;
}

Он не компилируется, и я не ожидаю, что он:

<source>:6:38: error: array initializer must be an initializer list
  explicit A(const int (&arr) [n]) : arr_(arr) {  }
                                     ^
<source>:14:8: note: in instantiation of member function 'A<3>::A' requested here
  A<3> a (arr);

Я не ожидаю, что он будет компилироваться по той же причине, по которой не компилируется следующее:

int main(int, char**) {
  const int arr_a [3] = { 1, 2, 3 };
  const int arr_b [3] = arr_a;

  return 0;
}

Вот ошибка компиляции:

<source>:3:13: error: array initializer must be an initializer list
  const int arr_b [3] = arr_a;
            ^

Но если вы в первом блоке кода закомментируете строку с пометкой (1), она будет компилироваться. Как будто, насколько я понимаю, есть способ назвать A::A(const int (&) [n]) действительным. На мой взгляд, даже попытка инициализировать arr_ с помощью arr неверна.

Почему компилируется первый блок кода, если вы закомментировали строку с пометкой (1)? Есть ли способ вызвать A::A(const int (&) [n]), который действителен?

Вы спрашиваете, почему const int arr [3] = { 1, 2, 3 }; компилируется?

AndyG 16.03.2018 10:48

Нет, я отредактировал свой вопрос, чтобы попытаться уточнить. Я спрашиваю, почему в конструкторе A компилируется arr_(arr). На мой взгляд, даже попытка инициализировать arr_ с помощью arr неверна.

user9408921 16.03.2018 10:50

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

Mohit 16.03.2018 10:51

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

Some programmer dude 16.03.2018 10:52

Может быть, тупик получше, но Почему классы шаблонов допускают функции, которые не могут компилироваться? актуален.

Baum mit Augen 16.03.2018 10:53

@Mohit Они должны нет использовать memcpy. std::copy, если нужно использовать массивы C, а лучше std::array.

Baum mit Augen 16.03.2018 10:53

@Mohit, я не ищу способ скопировать C-массив.

user9408921 16.03.2018 10:58

@BaummitAugen, я прочитал вашу ссылку и ветку комментариев ниже, но все еще не совсем понимаю. Я явно не понимаю, как компиляторы обрабатывают шаблоны, мне придется прочитать об этом. Например, это не компилируется, поэтому компилятор не полностью игнорирует определение. Это все необязательно? Что компиляторы не имеют смотрят определение, но они все равно смотрят?

user9408921 16.03.2018 11:37

@ryhp Компиляторам разрешено, но не обязательно, проверять синтаксис. В более общем плане им также разрешено обнаруживать любой шаблон, для которого никакой набор аргументов шаблона не приведет к правильно сформированному экземпляру, как в вашем примере.

Baum mit Augen 16.03.2018 11:38

@BaummitAugen, чтобы компилятор не смог успешно скомпилировать код, учитывая, что определение fn никогда не используется?

user9408921 16.03.2018 11:45

@BaummitAugen Я думаю, они должны проверить синтаксис; пример в предыдущем комментарии ryhp не должен компилироваться.

M.M 16.03.2018 11:46

@ M.M Не уверен на 100% в этом tbh, по крайней мере, MSVC явно не проверяет. Конечно, это довольно слабое доказательство. По этой теме есть Проверяются ли шаблоны C++ на наличие синтаксических ошибок без их создания?, но термин "синтаксическая ошибка", по-видимому, применяется там довольно слабо.

Baum mit Augen 16.03.2018 11:53
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
12
64
2

Ответы 2

Он не компилируется. Буквально. Вы не используете шаблон, поэтому компилятор даже не смотрит на него.

Компилятор смотрит на это. Вы не можете просто написать что-нибудь там.

AndyG 16.03.2018 10:53

@ryhp Это тоже не создает экземпляр функции-члена. См. Мою ссылку выше.

Baum mit Augen 16.03.2018 10:55

@ryhp Неявное создание экземпляра происходит только тогда, когда функция действительно используется.

llllllllll 16.03.2018 10:56

Ваш A имеет два конструктора, один действующий, а другой - нет. В вашем примере используется действительный.

Max Vollmer 16.03.2018 10:57

@MaxVollmer Ваша причина ошибочна, не имеет отношения к оптимизации.

llllllllll 16.03.2018 10:58

@ryhp Хотите верьте, хотите нет, но он также компилирует rextester.com/LPRW90518 (по крайней мере, на VC++).

Henri Menke 16.03.2018 10:58

@liliscent Я отредактировал свой комментарий, но мне любопытно: как не компилировать неиспользуемый метод, а не оптимизировать? Это предотвращает использование ненужного места для кода, который никогда не будет выполнен в результирующем исполняемом файле. Для меня это звучит как оптимизация.

Max Vollmer 16.03.2018 11:00

@HenriMenke Это плохо сформировано и не требует диагностики, как пример в OP, из-за 17.6 / 8.1 в N4659.

Baum mit Augen 16.03.2018 11:00

@MaxVollmer Оптимизация необязательна (кроме RVO в C++ 17 в некоторых случаях), а не создание экземпляров неиспользуемых шаблонов - нет. Оптимизация не меняет срок действия программы, в отличие от этого правила.

Baum mit Augen 16.03.2018 11:02

@BaummitAugen В том случае, о котором мы сейчас говорим, нет не созданного шаблона. Создается экземпляр шаблона, и один конструктор результирующего класса не компилируется, потому что он не используется. Почему это не оптимизация?

Max Vollmer 16.03.2018 11:05

@MaxVollmer Сам конструктор тоже является шаблоном; и поскольку он не вызывается, его определение должен не может быть реализовано. Это в общем-то не обязательно. См. Мою ссылку выше для подробностей. (В этом патологическом случае вещи могут вести себя иначе, поскольку код плохо сформирован, диагностика не требуется, потому что шаблон не может быть создан для любого параметра шаблона, но это угловой случай, касающийся основной точки.)

Baum mit Augen 16.03.2018 11:09

@BaummitAugen Спасибо за объяснение!

Max Vollmer 16.03.2018 11:16

Сообщение об ошибке на самом деле немного длиннее, чем вы цитировали. Он также отвечает на ваш вопрос:

test.cc:6:38: error: array initializer must be an initializer list
  explicit A(const int (&arr) [n]) : arr_(arr) {  }
                                     ^
test.cc:14:8: note: in instantiation of member function 'A<3>::A' requested here
  A<3> a (arr); // (1)
       ^

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

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

Что именно вы имеете в виду под "типографская правильность"? На мой взгляд, это означает что-то вроде, вместо ключевого слова for я написал dor или что-то еще. Но это не компилируется, хотя (на мой взгляд) типографически правильный.

user9408921 16.03.2018 12:05

Другие вопросы по теме