【问题标题】:Why do template template parameters with constraints require stricter arguments?为什么带有约束的模板模板参数需要更严格的参数?
【发布时间】:2013-12-30 22:52:44
【问题描述】:

N3580 描述了以下场景:

template<Object T, template<Object> Cont>
struct stack {
    Cont<T> container;
};

template<Object>
struct my_vector;

template<Regular>
struct my_list;

template<typename>
struct my_magic;

这里,RegularObject 的细化;也就是说,每个Regular 都是一个 Object 但不是每个Object 都是Regular

我希望类型系统能够使stack&lt;X, Y&gt; 有效, X 必须是 Object 并且 Y 必须可以用 Object 实例化。这 意味着stack&lt;int, my_vector&gt;stack&lt;int, my_magic&gt; 是有效的, 而stack&lt;int, my_list&gt; 不是。很像普通函数的情况:

struct Base {};
struct Derived : Base {};

void foo(Base* p, function<void(Base*)> fun) {
    fun(p);
}

template<typename T>
void bar(T*);

我希望如果pBase*,那么foo(p, bar&lt;Base&gt;)foo(p, bar<void>) 是有效的,而foo(p, bar&lt;Derived&gt;) 不是;毕竟,一个 Base* 隐式转换为void*,但没有转换为Derived*

但是,在模板的情况下,情况正好相反。仅有的 允许stack&lt;int, my_vector&gt;stack&lt;int, my_list&gt;,而禁止stack<int, my_magic>。为什么是这样? my_magic 适用于任何类型, 而my_list 可能会失败,具体取决于我给它的对象。此外,我可以 让my_magic 只使用对象:

template<Object T>
struct my_restricted_magic : my_magic<T> {};

现在my_restricted_magic 可以与stack 一起使用。另一方面,有 制作一个接受任何类型的my_list 并不容易,但这正是 现在允许将它作为模板模板参数传递。

我是否误解了模板模板参数约束的目的 参数?

【问题讨论】:

  • @KerrekSB N3580 是 C++1y 论文。 Bar 有一个类型参数,受 Object 概念约束。
  • @Yakk:哦,我明白了。我实际上读过一次。 (虽然它不是 in C++1y,是吗?)
  • @KerrekSB 不,这将是一个单独的 TS。
  • 我对这个问题有点困惑。你认为你的最后一行应该被允许吗?为什么?
  • @sftrabbit:我希望传递模板模板的工作方式与传递函数非常相似,而实际上恰恰相反。基本上,我期望逆变,但得到协方差。

标签: c++ templates constraints c++14


【解决方案1】:

这是提案中的一个错误。受约束的模板模板参数应接受具有较弱约束的参数。

【讨论】:

  • 谢谢!当前的行为(allowedforbidden)是否也倒退了?
  • 这是一个很好的问题,但我没有很好的答案。看起来你可以提出一个非常有说服力的论点,即 [allowed] 应该是一个错误,而 [forbidden] 应该是有效的。推理将遵循这里的参数:模板模板参数的签名宣布了参数的预期用途。
  • 呃。愚蠢的评论编辑系统。原因是模板模板参数的签名表达了参数的预期用途,而提供的参数不支持预期用途。对或错,标准要求该行为(14.3.3/3)。也许需要一份缺陷报告。
  • 嗯,这似乎是由 N2555 引入的,在实现 Boost 的 MPL 和 Proto 库时需要这样的匹配规则。似乎人们想要一种获取“可以是任何东西”的模板的方法,他们只是想用用户提供的参数包来实例化它。这不适合约束想要添加的元类型安全,但它看起来确实是一个有效的用例。谢谢,我会考虑提交缺陷报告。 (我认为[禁止]的情况绝对应该允许。)
  • @AntonGolov 请注意,我们没有“任何东西”,因为不能采用混合类型和值的 template,并且您不能拥有混合类型和值的包价值观。这是一种将您的 typename... 映射到一元模板的方法:ideone.com/3wX9o5 -- 如果允许/禁止被反转,我认为我不能以另一种方式编写这样的适配器。
【解决方案2】:

这是推测,但似乎是一种可能的解释:

允许传递更具体的模板,而不是更通用的模板,是当前规则在可变参数模板模板参数方面的工作方式。您可以在需要可变参数的地方传递单一类型参数模板:

template<template<typename...> class> struct Foo {};
template<typename> Bar {};

Foo<Bar>(); // legal

但反之亦然:

template<template<typename> class> struct Foo {};
template<typename...> Bar {};

Foo<Bar>(); // error, argument/parameter mismatch.

短语起源于 N2555,它被要求允许这样的代码:

template<typename>
struct Foo;

template<template<typename...> class Fun, template... Args>
struct Foo<Fun<Args...>> {};

Foo<std::pair<int, double>>();

基本上,template&lt;typename...&gt; class 不是对用户的保证,而是用户必须提供合理参数的包罗万象的东西。考虑到这种涉及专业化的用法,这似乎是合理的。

这并不能解释为什么不允许传递更通用的模板,但颠倒 N3580 中的措辞会使这两个规则放在一起相当不直观。

提案链接:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2555.pdf

【讨论】:

    猜你喜欢
    • 2021-09-04
    • 1970-01-01
    • 2019-12-10
    • 2014-09-08
    • 2021-10-22
    • 1970-01-01
    • 2011-10-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多