首页 文章

在模板模板参数的情况下,非类型模板参数的占位符类型是否可互换

提问于
浏览
18

考虑一个简单的例子:

int x;

template <template <auto> class TT>
struct Foo {
   void foo() {
      TT<(x)> tt;
      static_cast<void>(tt);
   }
};

template <decltype(auto)>
struct Bar { };


int main() {
    Foo<Bar> foobar;
    foobar.foo();
}

尽管在模板模板参数声明中使用 auto 没有问题,[clang]似乎也处理了 decltype(auto) 占位符的想法 .

另一方面[gcc] - 不是很好:

prog.cc:6:13:错误:'x'的值在常量表达式中不可用


通常 - 根据标准预期哪种行为?或许一切皆有可能,而且代码格式不正确(这次我想不是,但不能明确地排除它)?

PS . 很抱歉再次破坏其中一个编译器;)

1 回答

  • 7

    这里的原始答案是 Foo<Bar> 形成不良,我现在认为它的结构良好 . 但最终,clang bug基于 .


    我实际上认为即使Foo <Bar>也是不正确的 . 遵循P0522的新规则是:

    当P至少与模板参数A一样专用时,模板参数匹配模板模板参数P.

    哪里:

    模板模板参数P至少与模板模板参数A一样专用,如果给定以下两个函数模板的重写,则对应于P的函数模板至少与对应于A的函数模板一样专用 . 函数模板的部分排序规则([temp.func.order]) . 给定一个发明的类模板X,其模板参数列表为A(包括默认参数):两个函数模板中的每一个分别具有相同的模板参数,如P或A.每个函数模板都有一个函数参数,其类型为具有与来自相应功能模板的模板参数对应的模板参数的X的特化,其中,对于功能模板的模板参数列表中的每个模板参数PP,形成对应的模板参数AA . 如果PP声明参数包,则AA是包扩展PP ...([temp.variadic]);否则,AA是id-expression PP . 如果重写产生无效类型,那么P至少不像A那样专门化 .

    这意味着要验证 Foo<Bar> 本身是否正常,我们合成:

    template <decltype(auto) I> struct X;
    
    template <auto I>           void __f(X<I> ); // P
    template <decltype(auto) I> void __f(X<I> ); // A
    

    这里的所有类型都是有效的(因此最后一个语句在重载决策或选择类模板特化的上下文中都没有't apply). Now, typically when we do partial ordering it',在这种情况下我们要查找的是"more specialized"函数模板,其中 Fmore specialized than G 如果 F 至少与 G 一样专业, G 至少不像 F 那样专业 .

    但在这种情况下,我们并不关心哪种更专业 . 我们只需要 P 至少与 A 一样专业 . 所有这些意味着扣除必须从 AP 成功 . 因此,如果我们合成一些具有某个值 V 的唯一类型 U ,我们可以从 X<V> 中推导出 X<I> 吗?是 . 因此, P 至少与 A 一样专用,因此模板参数 Bar 与模板参数 TT 匹配 .


    现在,通过这一点,我会说这是一个铿锵的错误 . 模板模板参数是 template <auto> ,这是我们应该用来验证表达式的 . 使用非类型模板参数 auto ,我们尝试使用 x 作为值 - 但 x 不是有效的常量表达式,因此这应该失败 . clang似乎直接使用 template <decltype(auto) > - 我不确定它是否有效 .

    也就是说,我不确定这个案例是否已被考虑过 - 我没有看到任何措辞,并且值得提出一个问题 .

相关问题