Частичный вывод шаблона класса С++ 17

Мое понимание вопроса о выводе аргумента шаблона для шаблонов классов заключалось в гомогенизации поведения функций шаблона и классов шаблонов в контекстах вычета. Но я думаю, что я должен был что-то не понимать.

Если у нас есть этот шаблонный объект:

template <std::size_t S, typename T>
struct test
{
    static constexpr auto size = S;
    using type_t = T;

    test(type_t (&input)[size]) : data(input) {}
    type_t (&data)[size]{};
};

Я стараюсь использовать вспомогательную функцию в качестве синтаксического сахара для создания объектов test:

template <std::size_t S, typename T>
test<S, T> helper(T (&input)[S]) { return input; }

Что можно использовать, как показано ниже:

int main()
{
    int buffer[5];

    auto a = helper<5, int>(buffer); // No deduction
    auto b = helper<5>(buffer);      // Type deduced
    auto c = helper(buffer);         // Type and size deduced

    std::cout << a.size << b.size << c.size;

    return 0;
}

Вышеуказанный код выводит 555, как ожидалось. Я пробовал то же самое в Wandbox, используя новую настройку компилятора 1:

int main()
{
    int buffer[5];

    test<5, int> a(buffer); // No deduction: Ok.
    test<5> b(buffer);      // Type deduced: FAILS.
    test c(buffer);         // Type and size deduced: Ok.

    std::cout << a.size << b.size << c.size;

    return 0;
}

Похоже, что вывод аргумента шаблона для шаблонов классов работает только с выводом всех параметров, я ожидал, что оба поведения (вспомогательная функция и шаблон шаблона) будут одинаковыми, я что-то не понял?


1 Последними компиляторами в Wandbox являются gcc HEAD 7.0.1 201701 и clang HEAD 5.0.0 (trunk).

Ответы

Ответ 1

Из этого отличного отчета о поездке от Botond Ballo:

Первоначально предлагаемая функция включала в себя условие частичного вычета, в котором вы явно указываете некоторые аргументы шаблона и оставляете остальное для вывода, но это было вызвано опасениями, что в некоторых случаях это может быть очень запутанным:

// Would have deduced tuple<int, string, float>,
// but tuple<int> is a well-formed type in and of itself!
tuple<int> t(42, "waldo", 2.0f);

Ответ 2

Кажется, здесь существует противоречие. Глядя на P0091R3, кажется очевидным, что разрешается разрешать частично определяющие параметры:

Мы предлагаем разрешить имя шаблона ссылаться на шаблон класса как спецификатор простого типа или с частично предоставленными аргументами явного шаблона в двух контекстах:

Но фактическая формулировка стандартов в том же предложении не обеспечивает способ обработки "частично предоставленных аргументов явного шаблона". template-name, поскольку спецификатор простого типа не имеет аргументов шаблона.

Итак, следуя самой спецификации, поведение компилятора представляется правильным.