【问题标题】:C++17 class template partial deductionC++17类模板偏推
【发布时间】:2017-06-09 13:45:21
【问题描述】:

我对@9​​87654321@ 提案的理解是在演绎上下文中同质化模板函数和模板类的行为。但我认为我误解了一些东西。

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

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

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


1Wandbox 中最后可用的编译器是 gcc HEAD 7.0.1 201701clang HEAD 5.0.0 (trunk)。 p>

【问题讨论】:

  • type_t (&amp;data)[size]{}; 是数组引用吗? {} 是初始化程序吗?这能编译吗?另外,sintactic sugar 听起来很调皮。 :)
  • 请注意,adding an explicit deduction guide 没有帮助。我认为不支持部分扣除,因为标准根据 模板名称 (即没有&lt;...&gt; 语法)定义了扣除占位符。因此test&lt;5&gt; 不是有效的扣除占位符。
  • @Muscampester type_t (&amp;data)[size]{}; 是一个数组引用,是的。 {} 确实是初始化器,它编译 try it out!。关于sintactic sugar我能说什么... :'( 英语不是我的母亲,我犯了很多错误!
  • 据我所知,接受tuple&lt;int&gt; t{5, nullptr}; 之类的内容被认为是不可取的。

标签: c++ templates c++17


【解决方案1】:

来自 Botond Ballo 的出色 trip report

最初提议的功能包括部分推导的规定,您可以在其中明确指定一些模板参数,其余部分留待推导,但这是出于担心在某些情况下可能会非常混乱:

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

【讨论】:

  • 我觉得这个推理很奇怪。所以首先我们让std::make_tuple&lt;int&gt; (42, "waldo", 2.0f); 一直在做被认为是错误的事情,并告诉人们在推导模板参数时指定模板参数是错误的。现在通过禁止这一点,我们对类模板进行演绎,使其以与函数一不同的方式工作(不一致)并阻止大量有效用例(不同于人为的元组示例)。
  • @Predelnik:问题是现有代码可以使用 A&lt;T,U&gt; a(t,u,v)V 的默认模板参数(或长度为 2 而不是 3 的参数包)。你不敢默默地改变这种依赖完全可靠的缺乏演绎的意思。也许如果你只有显式的推导指南,那还好,但隐含的太危险了。
  • @DavisHerring 是的,打破现有代码似乎是一个更好的理由,但无法将其应用于合理的用例仍然令人遗憾。
  • 可以考虑添加占位符语法tuple&lt;int, _, _&gt; t(42, "waldo", 2.0f);
【解决方案2】:

这里似乎有矛盾。查看P0091R3,似乎很明显应该允许部分指定参数:

我们建议允许在两种上下文中引用类模板作为简单类型说明符或部分提供的显式模板参数的模板名称:

但同一提案中的实际标准措辞并未提供处理“部分提供的显式模板参数”的方法。 template-name 作为简单类型说明符不允许有模板参数。

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

【讨论】:

  • 是的,那篇论文尤其是一个相当令人震惊的案例,因为作者在修改措辞和设计时未能保持介绍部分的同步。不幸的是,结果是一个积极误导的介绍部分。
  • 幸好在他们想要进行最终投票之前还有另一个会议。
  • @MikelF:您假设他们实际上将允许部分规范。写作中的不一致表明这是委员会选择删除的内容,而不是原作者只是在措辞中犯了错误。
  • @NicoBolas 我实际上假设(或至少希望)是他们会使其保持一致。
  • 至少,有必要告知作者当前的实现会破坏一些东西。
猜你喜欢
  • 1970-01-01
  • 2017-12-30
  • 1970-01-01
  • 2019-12-25
  • 1970-01-01
  • 1970-01-01
  • 2018-02-15
  • 1970-01-01
  • 2021-04-17
相关资源
最近更新 更多