gpt4 book ai didi

c++ - C++ 20 : clang and gcc disagree中非类型文字参数对模板的部分特化

转载 作者:行者123 更新时间:2023-12-03 17:07:09 24 4
gpt4 key购买 nike

在c++ 20中使用literal, non-type template parameters玩弄时,我发现g++和clang++在以下代码上存在分歧。

#include <algorithm>

template<size_t N>
struct StringLiteral {
constexpr StringLiteral(const char (&str)[N]) {
std::copy_n(str, N, value);
}
char value[N];
};

template <typename T, StringLiteral Name>
struct named{};

template <typename T>
struct is_named: std::false_type{};

template <typename T, size_t N, StringLiteral<N> Name>
struct is_named<named<T, Name>>: std::true_type{};

// This will fail with g++
static_assert(is_named<named<int, "ciao">>::value == true);
透过Godbolt现场观看: https://godbolt.org/z/f3afjd
首先,我什至不确定自己是否以正确的方式进行操作:这是一种与通用 StringLiteral<N>类型匹配的方式吗?如果没有,正确的方法是什么?
而且,为什么编译器不同意呢?谁弄错了?

编辑:发现删除部分特化中的 size_t N参数会使两个编译器都同意,结果是预期的。像这样:
template <typename T, StringLiteral Name>
struct is_named<named<T, Name>>: std::true_type{};
但是,我仍然对我的第一次尝试是否合法(按标准)以及哪个编译器将其弄错感到好奇。

最佳答案

让我们关注is_named的部分特化:

template <typename T, size_t N, StringLiteral<N> Name>
struct is_named<named<T, Name>>: std::true_type{};

特别是尝试回答它是否违反了 [temp.class.spec.match]/3:

If the template arguments of a partial specialization cannot be deduced because of the structure of its template-parameter-list and the template-id, the program is ill-formed.


注意Clang显然不这么认为,并使用单个模板参数作为主模板来推导部分特化的所有模板参数。在这种特殊情况下,这些模板参数是与其模板参数列表匹配的参数:
  • 类型模板参数T
  • 的模板参数
  • 非类型模板参数N
  • 的模板参数
  • 非类型模板参数Name
  • 的模板参数

    根据 [temp.deduct.type]/4:

    [...] If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails. [...]


    我们可以将问题分解为部分特化的三个模板参数 TNName是否至少在一个推论上下文中使用。
    [temp.deduct.type]/1开始

    Template arguments can be deduced in several different contexts, but in each case a type that is specified in terms of template parameters (call it P) is compared with an actual type (call it A), and an attempt is made to find template argument values (a type for a type parameter, a value for a non-type parameter, or a template for a template parameter) that will make P, after substitution of the deduced values (call it the deduced A), compatible with A.


    [temp.deduct.type]/3和(再次) /4:

    /3 A given type P can be composed from a number of other types, templates, and non-type values:

    • [...]
    • A type that is a specialization of a class template (e.g., A<int>) includes the types, templates, and non-type values referenced by the template argument list of the specialization. [...]

    /4 In most cases, the types, templates, and non-type values that are used to compose P participate in template argument deduction.


    我们可以不失一般性地将主模板的单一类型模板参数的模板参数的实际类型考虑在内(我们打算将其作为要应用部分特化的类型家族的一部分),称为 A,作为 named<int, StringLiteral<5>{"ciao"}>
    根据部分特化的模板参数指定的类型为 P,即 named<T, Name>
  • T可以轻松推论,将A/Pnamed<int, StringLiteral<5>{"ciao"}>/named<T, Name>匹配到int,因为T中的named<T, Name>不在非推论上下文中。
  • Name同样不在非推论上下文中,并且可以推导为StringLiteral<5>{"ciao"}
  • 棘手的部分是N,它不是P的显式部分,而仅通过模板参数Name隐式地包含在其中。但是,这里我们可以简单地递归应用推导规则:Name已推导为StringLiteral<5>{"ciao"},这意味着我们考虑了一个新的A/PStringLiteral<5>/StringLiteral<N>,其中N在不可推论的上下文中为非,因此N最终可以是推导为5

  • And, why do the compilers disagree about it? Who's got the bug?


    因此,Clang(以及 MSVC)是正确的,可以接受您的原始变体,而GCC拒绝它是错误的(拒绝有效的错误)。
    Clang和MSVC(正确)接受并且GCC(错误)拒绝的一个更简单的示例是:
    template<int N>    struct S {};
    template<S s> struct U {};
    template<typename> struct V { V() = delete; };

    template <int N, S<N> s>
    struct V<U<s>> {};

    V<U<S<0>{}>> v{};
    // Expected: use partial specialization #1
    // GCC actual: error (rejects-valid): use of deleted function
    并且我使用以下示例提交了错误报告:
  • Bug 99699 - Type deduction failure for deducing a non-type template parameter via another deducible structural type (class template specialization) non-type template parameter

  • [...] removing the size_t N parameter in the partial specialization makes both compilers agree, [...]


    在您的第二个变体中,推导的情况并不像第一个那么复杂,并且您可以使用类似的分析来查看它的格式是否正确(可以推导部分特化的所有模板参数)。

    关于c++ - C++ 20 : clang and gcc disagree中非类型文字参数对模板的部分特化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66731338/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com