Вывод типа с rvalue initializer_list

В следующем коде

#include <initializer_list>
#include <utility>

template<typename T> void f(T&& x) {}
template<typename T> void g(std::initializer_list<T> x) {}

int main()
{
    auto   x = {0}; // OK
    auto&& y = {0}; // OK
    g(x); // OK
    g(std::move(x)); // OK
    g({0}); // OK
    f(x); // OK
    f(std::move(x)); // OK
    f({0}); // failure
    return 0;
}

rvalue initializer_list может быть выведено с помощью auto, но не с template.

Почему С++ запрещает это?

Ответ 1

Я считаю, что это связано с 14.8.2.1/1:

[...] аргумент списка инициализатора приводит к тому, что параметр считается невыводимым контекстом (14.8.2.5). [Пример: [...]

template<class T> void g(T);
g({1,2,3});                    // error: no argument deduced for T

- конец примера]

Теперь вы можете подумать, что auto - это только вычет аргумента шаблона, но для скопированных списков auto получает специальное обращение в 7.1.6.4/6:

заменяя вхождения auto либо новым шаблоном шаблона типа U, либо, если инициализатор является скобкой-init-list (8.5.4), с std::initializer_list<U>. [...] [Пример:

auto x1 = { 1, 2 };   // decltype(x1) is std::initializer_list<int>

- конец примера]