首页 > 解决方案 > 可以将其类型用推导类类型的占位符指定的非类型模板参数传递给 C++2a 中的另一个模板吗?

问题描述

template<auto>
struct S {};

template<S>
struct T {};

using T0 = T<S<0>{}>; // compiles

template<S s>
using T1 = T<s>; // fails

T0使用 GCC 9.1 编译但T1不:

error: class template argument deduction failed
error: no matching function for call to 'S(S<...auto...>)'

这是 C++2a 中的预期行为吗?

编辑: 每当推导类型时,编译失败似乎都会发生,而不是特别是在使用推导类类型的占位符时:

template<auto s>
using T1 = T<s>; // also fails

标签: c++templatesc++20

解决方案


T0应该是病态的,因为S<0>不具有很强的结构平等性。

T1应该是不正确的,不需要诊断,因为就目前而言,没有任何专业化T1是有效的(因为没有专业化S具有很强的结构平等性)。


这是因为对类类型作为非类型模板参数的要求来自[temp.param]/4

非类型模板参数应具有以下类型之一(可选 cv 限定):

  • 具有强结构相等性的文字类型([class.compare.default]),
  • 左值引用类型,
  • 包含占位符类型 ([dcl.spec.auto]) 的类型,或
  • 推导类类型的占位符 ([dcl.type.class.deduct])。
template<S>
struct T {};

属于最后一种情况。但是当我们尝试时,我们从 CTAD中T<S<0>{}>推断出占位符 ,我们点击[temp.arg.nontype]/1SS<0>

如果模板参数声明([temp.param])不允许推导参数类型,则程序格式错误。

这让我们回到了最初的参考,现在我们需要一种叫做“强结构平等”的东西。这在[class.compare.default]/4中定义为:

如果给定type的左值,则类型 C 具有强结构相等性xconst C

  • C是非类类型,并且x <=> x是类型std::strong_­orderingor的有效表达式std::strong_­equality,或

  • C是一个类类型,其中所有以下内容都成立:

    • 的所有C基类子对象和非静态数据成员都具有很强的结构相等性。
    • C没有可变或易失的非静态数据成员。
    • 在 的定义结束时C,为表达式执行的重载决策成功并找到在 的定义中定义为默认值x == x的友元或公共成员运算符。==C

在我们的例子中,我们是一个类类型,但是虽然我们所有的子对象都具有很强的结构相等性(很简单,因为我们没有子对象),但我们没有适当的operator==. 要解决这个问题:

template <auto>
struct S {
    friend bool operator==(S const&, S const&) = default;
};

现在一切都应该编译(但不是因为 gcc 还不完全支持这一点,实际上甚至不允许你声明所需的 defaulted operator==)。


推荐阅读