C++17 class 模板部分推导

C++17 class template partial deduction

我对 Template argument deduction for class templates 提议的理解是在演绎上下文中使模板函数和模板 classes 的行为同质化。但是我觉得我误会了什么。

如果我们有这个模板对象:

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;
}

看起来 class 模板的模板参数推导只适用于推导所有参数,我期望两种行为(辅助函数和 class 模板)是相同的,我是不是误解了什么?


1Wandbox 中最后可用的编译器是 gcc HEAD 7.0.1 201701clang HEAD 5.0.0 (树干).

这里好像有点矛盾。查看 P0091R3,似乎很清楚应该允许部分指定参数:

We propose to allow a template name referring to a class template as a simple-type-specifier or with partially supplied explicit template arguments in two contexts:

但同一提案中的实际标准措辞并未提供处理"partially supplied explicit template arguments"的方法。 template-name 因为 simple-type-specifier 不允许有模板参数。

因此,按照规范本身,编译器的行为似乎是正确的。

来自 Botond Ballo 的这篇优秀 trip report

The feature as originally proposed included a provision for partial deduction, where you explicitly specify some of the template arguments, and leave the rest to be deduced, but this was pulled over concerns that it can be very confusing in some cases:

// 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);