С++ 1z динамическая ошибка спецификации исключения

Я пытаюсь скомпилировать свой проект с новой версией GCC 7.2.1 и иметь проблемы с динамическими спецификациями исключений:

error: ISO C++1z does not allow dynamic exception specifications
  MEMORY_ALLOC_OPERATORS(SQLException)

Проблема в том, что эти ошибки исходят от сторонних библиотек, которые я не контролирую.

Есть ли способ исправить это? Насколько я знаю, я не могу сказать компилятору заменить ошибки предупреждениями. Использование --std=c++14 не является опцией, потому что я хочу использовать новые функции из С++ 1z.

Ответ 1

С++ 17 удалил динамические спецификации исключений в результате P0003. До этого они были устаревшими с С++ 11. Они больше не являются частью языка, поэтому на самом деле нет способа исправить это. Пока вам нужна эта сторонняя библиотека, пока она не изменится, вы застряли на С++ 14.


Если вы в отчаянии, вы можете попробовать:

#define throw(...)

но я бы не рекомендовал его.

Ответ 2

Ну, я написал небольшой обходной путь.

#if __cplusplus >= 201703L
    /* MySQL override. This needed to be inclided before cppconn/exception.h to define them */
    #include <stdexcept>
    #include <string>
    #include <memory>

    /* Now remove the trow */
    #define throw(...)
    #include <cppconn/exception.h>
    #undef throw /* reset */
#endif

Краткое объяснение: если мы используем С++ 17, throw больше не разрешен для распределителей. Если вы внимательно посмотрите на заголовок библиотеки, то увидите, что существует определенный макрос, который содержит определения для распределителя по умолчанию в библиотеке. К сожалению, он не может быть переопределен, потому что он определен там, игнорируя, который может быть уже определен. Так или иначе, вы все равно должны отвергнуть дроу.

Основная хитрость заключается в переопределении функции trow с помощью макроса. Это приводит нас к проблеме, что мы также переопределяем оператор trow для всех включений в библиотеке, что не является хорошим решением (а также не работает). Как вы, возможно, знаете, если вы включаете заголовок, он будет включен только один раз (в основном, благодаря защите заголовков). Таким образом, хитрость заключается в том, чтобы включить заголовки, которые включены библиотекой, а затем переопределить бросок, включающий заголовок целевой библиотеки, который фактически не включает их заголовок снова, потому что мы уже это сделали.

Ответ 3

  1. Слой изоляции, как упомянуто, как упомянуто в комментарии выше. Что-то вроде:

#if __cplusplus < 201703L//Standards below C++2017

 void fn() throw (int) { }

#endif//__cplusplus

  1. Самое время, чтобы вы начали заменять throw(whatever) на noexcept(false).

В любом случае, будьте готовы повеселиться!

Ответ 4

Иди в эту же проблему, поэтому мне пришлось изменить это определение макроса в /usr/include/cppconn/exception.h:

#define MEMORY_ALLOC_OPERATORS(Class) \
void* operator new(size_t size) noexcept(false) { return ::operator new(size); }  \
void* operator new(size_t, void*) noexcept; \
void* operator new(size_t, const std::nothrow_t&) noexcept; \
void* operator new[](size_t) noexcept(false); \
void* operator new[](size_t, void*) noexcept; \
void* operator new[](size_t, const std::nothrow_t&) noexcept; \
void* operator new(size_t N, std::allocator<Class>&);

Ответ 5

В MSVC ваш спецификатор throw (...) всегда был фактически пустым пространством. Например, Visual Studio всегда беззвучно компилировала такую функцию:

void SomeFunction() throw(std::string) {...} 

КАК ЕСЛИ это было:

void SomeFunction() {...}

или в современном С++ 11 и далее:

void SomeFunction() noexcept(false) {...}

Итак, для 99% всех кроссплатформенных 3P-пакетов макро и #include взломаны с акцентом на:

#define throw(...) 

будут работать немедленно, потому что пакетные сборки Windows уже молча делают то, что делает этот макрос. В противном случае вы можете обернуть все вызовы & ссылки на нарушающие интерфейсы в паре ваших собственных исходных файлов на С++ 14. Это по крайней мере позволит остальной части вашего проекта использовать c ++ 17.