Я сам очень редко использую 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]), который действителен?
Нет, я отредактировал свой вопрос, чтобы попытаться уточнить. Я спрашиваю, почему в конструкторе A компилируется arr_(arr). На мой взгляд, даже попытка инициализировать arr_ с помощью arr неверна.
почему бы вам не использовать memcpy для копирования массивов.
Шаблон не является фактическим классом до его создания. Это первое, когда вы создаете экземпляр шаблона, класс существует и его можно проверить на наличие ошибок так же, как и другие классы.
Может быть, тупик получше, но Почему классы шаблонов допускают функции, которые не могут компилироваться? актуален.
@Mohit Они должны нет использовать memcpy. std::copy, если нужно использовать массивы C, а лучше std::array.
@Mohit, я не ищу способ скопировать C-массив.
@BaummitAugen, я прочитал вашу ссылку и ветку комментариев ниже, но все еще не совсем понимаю. Я явно не понимаю, как компиляторы обрабатывают шаблоны, мне придется прочитать об этом. Например, это не компилируется, поэтому компилятор не полностью игнорирует определение. Это все необязательно? Что компиляторы не имеют смотрят определение, но они все равно смотрят?
@ryhp Компиляторам разрешено, но не обязательно, проверять синтаксис. В более общем плане им также разрешено обнаруживать любой шаблон, для которого никакой набор аргументов шаблона не приведет к правильно сформированному экземпляру, как в вашем примере.
@BaummitAugen, чтобы компилятор не смог успешно скомпилировать код, учитывая, что определение fn никогда не используется?
@BaummitAugen Я думаю, они должны проверить синтаксис; пример в предыдущем комментарии ryhp не должен компилироваться.
@ M.M Не уверен на 100% в этом tbh, по крайней мере, MSVC явно не проверяет. Конечно, это довольно слабое доказательство. По этой теме есть Проверяются ли шаблоны C++ на наличие синтаксических ошибок без их создания?, но термин "синтаксическая ошибка", по-видимому, применяется там довольно слабо.





Он не компилируется. Буквально. Вы не используете шаблон, поэтому компилятор даже не смотрит на него.
Компилятор смотрит на это. Вы не можете просто написать что-нибудь там.
@ryhp Это тоже не создает экземпляр функции-члена. См. Мою ссылку выше.
@ryhp Неявное создание экземпляра происходит только тогда, когда функция действительно используется.
Ваш A имеет два конструктора, один действующий, а другой - нет. В вашем примере используется действительный.
@MaxVollmer Ваша причина ошибочна, не имеет отношения к оптимизации.
@ryhp Хотите верьте, хотите нет, но он также компилирует rextester.com/LPRW90518 (по крайней мере, на VC++).
@liliscent Я отредактировал свой комментарий, но мне любопытно: как не компилировать неиспользуемый метод, а не оптимизировать? Это предотвращает использование ненужного места для кода, который никогда не будет выполнен в результирующем исполняемом файле. Для меня это звучит как оптимизация.
@HenriMenke Это плохо сформировано и не требует диагностики, как пример в OP, из-за 17.6 / 8.1 в N4659.
@MaxVollmer Оптимизация необязательна (кроме RVO в C++ 17 в некоторых случаях), а не создание экземпляров неиспользуемых шаблонов - нет. Оптимизация не меняет срок действия программы, в отличие от этого правила.
@BaummitAugen В том случае, о котором мы сейчас говорим, нет не созданного шаблона. Создается экземпляр шаблона, и один конструктор результирующего класса не компилируется, потому что он не используется. Почему это не оптимизация?
@MaxVollmer Сам конструктор тоже является шаблоном; и поскольку он не вызывается, его определение должен не может быть реализовано. Это в общем-то не обязательно. См. Мою ссылку выше для подробностей. (В этом патологическом случае вещи могут вести себя иначе, поскольку код плохо сформирован, диагностика не требуется, потому что шаблон не может быть создан для любого параметра шаблона, но это угловой случай, касающийся основной точки.)
@BaummitAugen Спасибо за объяснение!
Сообщение об ошибке на самом деле немного длиннее, чем вы цитировали. Он также отвечает на ваш вопрос:
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 или что-то еще. Но это не компилируется, хотя (на мой взгляд) типографически правильный.
Вы спрашиваете, почему
const int arr [3] = { 1, 2, 3 };компилируется?