MSVC 和 GCC 受 std::driven_from 约束的部分模板专业化编译方式不同

Wan*_*nze 5 c++ language-lawyer c++20

#include <concepts>

class Base {};

class Derived : public Base {};

// primary template
template <typename T>
    requires std::derived_from<T, Base>
struct C {
    static constexpr int value = 1;
};

// specialization
template <typename T>
    requires std::derived_from<T, Derived>
struct C<T> {
    static constexpr int value = 2;
};

static_assert(C<Derived>::value == 2);
Run Code Online (Sandbox Code Playgroud)

事实证明,MSVC 可以很好地编译代码 ( godbolt ),而 GCC 拒绝编译并显示错误消息 ( godbolt ):

错误:部分特化“struct C”不特化任何模板参数,并且不比主模板受到更多约束

我想知道根据语言标准,哪种行为是正确的,以及专门针对C++20 中C<T>所有T派生自Derived(而不是Base)(包括自身)的正确方法是什么。Derived

use*_*522 5

海湾合作委员会是正确的。

std::derived_from<T, Derived>不包含 std::derived_from<T, Base>,因此部分特化并不比主模板更特化,这是不允许的。

这是从[temp.spec.partial.general]/9.2[temp.spec.partial.order][temp.func.order]/6.4[temp.constr.order]/1.2以及最后[temp.constr .原子]/2

std::derived_from<T, X>包含约束的合取,其中一个出于示例目的而选择的为std::is_base_of_v<X, T>

std::is_base_of_v不是一个概念,而是一个变量模板。因此,主模板具有原子约束std::is_base_of_v<X, Base>,而专业化则具有原子约束std::is_base_of_v<X, Derived>。这两个原子约束并不等同。因此,在模板的两个约束中,没有一个比另一个更专业。

为了确保部分专业化的约束包含主要专业化的约束,您需要

template <typename T>
    requires std::derived_from<T, Base> && std::derived_from<T, Derived>
struct C<T> { //...
Run Code Online (Sandbox Code Playgroud)

现在这些约束包含了主模板上的约束。


另请注意,这不仅仅是如何实现约束/概念的问题:

std::derived_from<T, Derived>并且Derived源自Base并不意味着std::derived_from<T, Base>.​

std::derived_from要求基础是明确的并且是可访问的。最后一部分与 不同std::is_base_of

例子:

struct A {};
struct B : A {};
struct C : A {};
struct D : B, C {};

static_assert(std::derived_from<B, A>);
static_assert(std::derived_from<D, B>);
static_assert(!std::derived_from<D, A>);
Run Code Online (Sandbox Code Playgroud)

另一个:

struct A {};
struct B : private A {};
struct D : B {};

static_assert(std::derived_from<B, A>);
static_assert(std::is_base_of<B, D>);
static_assert(!std::derived_from<D, A>);
Run Code Online (Sandbox Code Playgroud)

  • 我想知道标准在哪里说专业化的约束必须包含主要模板的约束。毕竟,这是一个语言律师问题。 (5认同)
  • @HolyBlackCat https://wg21.link/temp.spec.partial.general#9.2 (2认同)