Ошибка компиляции после обновления до gcc 9 при использовании концептов с пакетом аргументов в if constexpr - PullRequest
0 голосов
/ 26 октября 2019

У меня есть код, который использует концепцию с пакетом аргументов в контексте if constexpr. Раньше он компилировался и работал в gcc 8, но ломался в gcc 9:

#include <utility>
#include <tuple>

template <typename T, typename ...Ts>
concept
#if __GNUC__ < 9
bool
#endif
is_handled = requires(T handler, Ts && ...args) {
    handler.handle(std::forward<Ts>(args)...);
};

template <typename T>
concept
#if __GNUC__ < 9
bool
#endif
has_name = requires(T) {
    T::name;
};

template <typename ...Handlers>
struct Dispatcher {

    template <typename ...Ts>
    void operator()(Ts && ...args) {
        std::apply(
            [&](auto && ...handlers) {
                (handle(handlers, std::forward<Ts>(args)...),...); 
            },
            m_handlers
        );
    }

private:
    template <typename Handler, typename ...Ts>
    void handle(Handler & handler, Ts && ...args) {
        if constexpr (is_handled<Handler, Ts...>) {
            handler.handle(std::forward<Ts>(args)...);
        }
    }

    template <typename Handler>
    char const* get_code() {
        if constexpr (has_name<Handler>) {
            return Handler::name;
        }
        return nullptr;
    }

    std::tuple<Handlers...> m_handlers;
};

Ошибка, создаваемая GCC 9.2:

<source>: In member function 'void Dispatcher<Handlers>::handle(Handler&, Ts&& ...)':
<source>:38:49: error: expected unqualified-id before ')' token
   38 |         if constexpr (is_handled<Handler, Ts...>) {
      |                                                 ^

См. Проводник компилятора здесь . Вы можете переключаться между версиями gcc 8.3 и 9.2, чтобы увидеть разницу.

1 Ответ

4 голосов
/ 26 октября 2019

Вы правы в том, что он должен скомпилироваться и что это регрессия в GCC 9.1.

Для этого уже есть отчет об ошибке в трекере ошибок GCC здесь .

Вы можете избежать ошибки синтаксического анализатора, поместив дополнительные скобки вокруг условия if constexpr, заставив его анализироваться как выражение вместо объявления:

if constexpr ((is_handled<Handler, Ts...>)) {
    //...
}
...