Подтвердить что ты не робот

Обработка предупреждения gcc noexcept

Рассмотрим этот пример: ошибка 80985:

template <class Func>
void call(Func f)
{
    f();
}

void func() noexcept { }

int main()
{
    call(func);
}

Компиляция с учетом всех предупреждений, как и вы, дает:

$ g++ -std=c++14 -Wall foo.cxx 
foo.cxx:2:6: warning: mangled name for ‘void call(Func) [with Func = void (*)() noexcept]’ will change in C++17 because the exception specification is part of a function type [-Wnoexcept-type]
 void call(Func f)
      ^~~~

Что именно я должен делать с этим предупреждением? Что такое исправление?

4b9b3361

Ответ 1

Есть несколько вещей, которые вы можете сделать с предупреждением.

Отключите его с помощью -Wno-noexcept-type. Во многих проектах предупреждающее сообщение бесполезно, потому что нет никакого шанса, что результирующий объект будет связан с другим объектом, который ожидает, что он будет использовать GCC С++ 17. Если вы не компилируете с различными настройками -std=, и вы не создаете статическую или разделяемую библиотеку, где функция нарушения является частью ее открытого интерфейса, тогда предупреждающее сообщение может быть безопасно отключено.

Скомпилируйте весь свой код с помощью -std=c++17. Предупреждающее сообщение исчезнет, ​​так как функция будет использовать новое искаженное имя.

Сделайте функцию static. Поскольку функция больше не может ссылаться на другой объектный файл с использованием другого механизма для функции, предупреждение не будет отображаться. Определение функции должно быть включено во все блоки компиляции, которые его используют, но для функций шаблонов, подобных вашему примеру, это обычное явление. Также это не будет работать для функций-членов, если static означает что-то еще.

При вызове шаблона функции укажите параметр шаблона, явно указывающий тип совместимого типа функции, который не имеет спецификации исключения. Например call<void (*)()>(func). Вы также должны иметь возможность использовать cast, чтобы сделать это, но GCC 7.2.0 все еще генерирует предупреждение, хотя использование -std=c++17 не изменяет mangling.

Если функция не является шаблоном, не используйте noexcept с любыми типами указателей функций, используемых в типе функции. Этот и последний пункт полагаются на то, что только типы указателей функций без метаданных приводят к изменениям именования изменений и что могут быть назначены указатели на ненулевые функции (С++ 11) или неявно преобразованные (С++ 17), чтобы, возможно, метать указатели функций.

Ответ 2

Я поддерживаю ответ Росса для решения call<void (*)()>(func). Он явно сообщает компилятору, что вы хотите, чтобы шаблон был создан для типа функции не noexcept, и гарантирует, что ваш код будет работать точно так же в С++ 17, как это было в С++ 14.

Другие альтернативы:

(1) Оберните функцию noexcept в лямбда (которая не является noexcept):

template <class Func>
void call(Func f)
{
    f();
}

void func() noexcept { }

int main()
{
    call([]() { func(); });
}

(2) Создайте отдельную оболочку без noexcept. Это больше набирается на начальном этапе, но если у вас есть несколько сайтов для вызова, это может сохранить типизацию в целом. Это то, что я закончил делать в коде, который изначально побудил меня записать ошибку GCC.

Ответ 3

Проблема, о которой они вас предупреждают, заключается в том, что в С++ 14 это будет работать:

void call(void (*f)())
{
    f();
}

void func() noexcept {}

int main(int argc, char* argv[])
{
    call(&func);
    return 0;
}

но в С++ 17 вам нужно будет изменить объявление call следующим образом:

void call(void (*f)() noexcept)
{
    f();
}

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

Например, этот код будет скомпилирован в С++ 14, но не С++ 17:

void foo() noexcept {}
void bar()          {}

template <typename F>
void call(bool b, F f1, F f2)
{
    if (b)
        f1();
    else
        f2();
}

void foobar(bool b)
{
    call(b, &foo, &bar);
}

В С++ 14 типы foo и bar совпадают, но они различаются в С++ 17, то есть разрешение шаблона не удастся. Сообщение об ошибке в gcc 7.2 с флагом -std=c++1z:

note:   template argument deduction/substitution failed:
note:   deduced conflicting types for parameter 'F' ('void (*)() noexcept' and 'void (*)()')

В примере, который вы указали, нет проблемы, и у вас не будет проблем с компиляцией в режиме С++ 14 или С++ 17. Если код более сложный, чем пример здесь (например, аналогичный приведенным выше примерам), вы можете столкнуться с некоторыми проблемами с компилятором. Кажется, у вас есть недавний компилятор; попробуйте выполнить компиляцию с помощью -std=c++1z и посмотрите, есть ли предупреждения или ошибки.