Руководство по варидической дедукции, не принятое g++, взято clang++ - кто прав?

Рассмотрим следующий код:

template <typename... Types>
struct list
{
    template <typename... Args>
    list(Args...) 
    {
        static_assert(sizeof...(Types) > 0);
    }
};

template <typename... Args>
list(Args...) -> list<Args...>;

int main()
{
    list l{0, 0.1, 'a'};
}

Я ожидаю, что decltype(l) будет list<int, double, char>. К сожалению, g++ 7.2 и g++ trunk не дают статического утверждения. clang++ 5.0.0 и clang++ trunk компилируются и работают как ожидалось.

вид соответствия godbolt.org

Это ошибка g++? Или есть причина, почему руководство по вычету не следует соблюдать здесь?


Добавление ограничения SFINAE для конструктора, по-видимому, обеспечивает желаемое поведение:

template <typename... Args, 
          typename = std::enable_if_t<sizeof...(Args) == sizeof...(Types)>>
list(Args...) 
{
    static_assert(sizeof...(Types) > 0);
}

вид соответствия godbolt.org

Ответы

Ответ 1

Это gcc ошибка 80871. Проблема в том, что мы заканчиваем этот набор кандидатов для вычета:

template <class... Types, class... Args>
list<Types...> __f(Args... ); // constructor

template <class... Args>
list<Args...>  __f(Args... ); // deduction-guide

Оба действительны (Types...может выводить как пустые в первом случае), но вызов здесь должен быть неоднозначным - ни один из них не является более специализированным, чем другой. Types... здесь не участвует (похоже на пример в [temp.deduct.partial]/12). Поэтому правильное поведение - перейти к следующему тай-брейку, который выступает за вычитание-руководства. Следовательно, это должно быть list<int, double, char>.

Однако поведение gcc должно способствовать конструктору, поэтому триггеры static_assert becusase Types... действительно были бы пустыми в этой ситуации.