Intel C++ не может преобразовать 'T * `' в ' T const * const *', GCC может
Проблема
расширение существующего кода
у меня есть числовая библиотека, которая была разработана с одним "вкусом" в виду. Теперь я хочу обобщить это. Основная структура данных-это "спинор", который сама по себе многомерная матрица. Есть много функций, которые принимают массивы этих спиноров. Обобщенные функции должны принимать один такой спинор массив для каждого вкуса.
скажем, есть функция, которая, как минимум, делает следующий:
void copy_spinor(Spinor *out, const Spinor *in) {
std::cout << out << " " << in << "n";
}
мое обобщение вот этого:
void copy_spinor(Spinor *out[num_flav], const Spinor *const in[num_flav]) {
std::cout << "Fwd: ";
copy_spinor(out[0], in[0]);
}
в реальном коде есть цикл по всем num_flav
, но это не реально
необходимо для этой демонстрации здесь.
насколько я понимаю, это нужно читать как const Spinor *(in[num_flav])
,
так что in
является указателем на массив вероятно num_flav
элементы (или другой
количество, потому что foo[]
это просто *foo
в параметре функции) типа
указатель на Конст-спинор.
в проблема в том, что он не компилируется при использовании Spinor *non_const[2]
(без const
), см. мой раньше
вопрос. Из ответа там я
узнали, что это не должно компилироваться, потому что внутри функции
copy_spinor
указатель non_const[0]
можно указать на некоторые
const
массив Spinor *
. Тогда non_const
бы const
данные.
Поэтому это не работает.
мой вывод заключался в том, что добавление другое const
сделать это правильно:
void copy_spinor(Spinor *out[num_flav], const Spinor *const in[num_flav]) {}
когда я сейчас пройду мой non_const
в качестве второго параметра, функция не может
изменить in[0]
на что угодно, потому что этот указатель теперь неизменен. Это
служил мне хорошо с GCC 6.3. Теперь идя в производство с Intel C++ 17, он
больше не работает.
минимальный рабочий пример следующий:
#include <cstdint>
typedef float Spinor[3][4][2][8];
template <uint8_t num_flav>
class Solver {
public:
void copy_spinor(Spinor *out, const Spinor *in) {
std::cout << out << " " << in << "n";
}
void copy_spinor(Spinor *out[num_flav], const Spinor *const in[num_flav]) {
std::cout << "Fwd: ";
copy_spinor(out[0], in[0]);
}
};
int main(int argc, char **argv) {
Spinor *s1 = new Spinor[10];
Spinor *s2 = new Spinor[10];
Spinor *s1_a[1] = {s1};
Spinor *s2_a[1] = {s2};
Solver<1> s;
s.copy_spinor(s2_a, s1_a);
}
на GCC он, по-видимому, разрешает второй copy_spinor
перегрузка. Этот
переменная s1_a
который принимает роль предыдущий non_const
разрешается
аргумент.
проблемы с Intel C++ 17
Intel C++ 17 однако, не принимает, что:
$ icpc -Wall -pedantic const-spinor-const.cpp --std=c++11
const-spinor-const.cpp(23): error: no instance of overloaded function "Solver<num_flav>::copy_spinor [with num_flav=(uint8_t={unsigned char})'1']" matches the argument list
argument types are: (Spinor *[1], Spinor *[1])
object type is: Solver<(uint8_t)'1'>
s.copy_spinor(s2_a, s1_a);
^
const-spinor-const.cpp(11): note: this candidate was rejected because arguments do not match
void copy_spinor(Spinor *out[num_flav], const Spinor *const in[num_flav]) {}
^
const-spinor-const.cpp(10): note: this candidate was rejected because arguments do not match
void copy_spinor(Spinor *out, const Spinor *in) {}
^
сообщение об ошибке не особенно полезно, потому что он не говорит, что
обращение не было разрешено. Просто кажется, что const
проблема.
возможно, что-то я пропустил с Intel C++? Это отсутствие функции или использовал ли я неофициальное расширение GCC? Это ошибка в Intel C++ или GCC?
обновление: пример также компилируется с текущим Clang.
Класс Без Шаблона
та же проблема сохраняется, когда класс Solver
не является классом шаблона.
С T a[2]
это то же самое, что T a[2]
и T *a
в аргументе функции, я могу
также просто напишите функцию, как это, не нуждаясь в uint8_t num_flav
:
void copy_spinor(Spinor *out[], const Spinor *const in[]) {
std::cout << "Fwd: ";
copy_spinor(out[0], in[0]);
}
ошибка та же.
свободный Функции
та же проблема также возникает для функций non-member non-friend non-template:
void free_spinor(Spinor *out, const Spinor *in) {
std::cout << out << " " << in << "n";
}
void free_spinor(Spinor *out[], const Spinor *const in[]) {
std::cout << "Fwd: ";
free_spinor(out[0], in[0]);
}
сообщение об ошибке такое же:
$ icpc -Wall -pedantic const-spinor-const.cpp --std=c++11
const-spinor-const.cpp(97): error: no instance of overloaded function "free_spinor" matches the argument list
argument types are: (Spinor *[1], Spinor *[1])
free_spinor(s2_a, s1_a);
^
const-spinor-const.cpp(30): note: this candidate was rejected because arguments do not match
void free_spinor(Spinor *out[], const Spinor *const in[]) {
^
const-spinor-const.cpp(26): note: this candidate was rejected because arguments do not match
void free_spinor(Spinor *out, const Spinor *in) {
^
Попытки Решения
чтобы запустить код в производстве, я вижу следующие параметры. Никто из они особенно привлекательны.
что было бы хорошим способом идти вперед? Я могу изменить мои новые функции все я хотите, но я хотел бы избежать касания кода вызывающего абонента как насколько это возможно.
Const Обертки
когда я изменяю определение s1_a
на
1 ответов
GCC и clang прямо здесь, Intel C++ ошибается.
соответствующая часть стандарта квалификация преобразования [conv.qual]
(номер раздела может быть 4.4 или 4.5). Формулировка изменилась между C++11 и C++1z (чтобы стать C++17)... но ваш код, который добавляет const
на нескольких уровнях, начиная с самого мелкого, допускается во всех версиях (C++03, 11, 14, 1z).
одно изменение заключается в том, что теперь применяется многоуровневое правило const к массивам указателей, где раньше он применялся только к нескольким указателям. Но на самом деле мы имеем дело с множественным указателем, потому что синтаксис массива, найденный в объявлении параметра, имеет семантику указателя.
тем не менее, возможно, стоит попробовать
void copy_spinor(Spinor **out, const Spinor *const *in)
в случае, если компилятор запутался / не смог настроить типы массивов для типов указателей в списке параметров функции перед применением правила.