Reputation: 117
I have a code that uses a concept with argument pack in if constexpr
context. It used to compile and work in gcc 8 but breaks in 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;
};
The error produced by GCC 9.2 is:
<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...>) {
| ^
See compiler explorer here. You can switch between gcc versions 8.3 and 9.2 to see the difference.
Upvotes: 0
Views: 530
Reputation: 22152
You are correct that it should compile and that it is a regression in GCC 9.1.
There is already a bug report for this in GCC's bug tracker here.
You can avoid the parser bug by placing additional parentheses around the if constexpr
condition, forcing it to be parsed as expression instead of declaration:
if constexpr ((is_handled<Handler, Ts...>)) {
//...
}
Upvotes: 4