为什么不验证模板模板参数中的概念?

Why is the concept in template template argument not verified?

C++20 允许程序为模板模板参数指定概念。例如,

#include <concepts>

template <typename T> concept Char = std::same_as<T, char>;
template <typename> struct S {};
template <template <Char U> typename T, typename U> T<U> foo() { return {}; }

int main() { foo<S, int>(); }

函数 foo 的第一个模板参数应为单个参数模板。

概念 Char 被定义为仅类型 char 为真,因此尝试满足 int 将失败。以上程序仍被所有编译器接受:https://gcc.godbolt.org/z/PaeETh6GP

能不能解释一下,为什么template模板参数中的概念可以指定,但还是会被忽略?

模板(实际)参数匹配模板(正式)参数,如果后者至少为专门化 为前者。

template <Char> typename Ttemplate <typename> struct S 更专业。粗略地说,template <Char> 接受了 template <typename> 接受的子集(“至少像专业化”实际意味着什么的确切定义相当复杂,但这是第零个近似值)。

这意味着实参可以在所有可以使用形参的上下文中使用。也就是说,对于 T<K> 有效的任何类型 KS<K> 也是有效的(因为 S<K> 对任何 K 都有效)。

所以可以用S代替T

如果反过来:

template<typename T> concept Any = true; 
template<typename T> concept Char = Any<T> && std::same_as<T, char>;

template<template<Any> class T> void foo();
          
template<Char> struct S { };
          
int main()  
{           
    foo<S>(); 
}

那么这是错误的,因为(大致上)你可以说 T<int> 而不是 S<int>。所以 S 不是 T.

的有效替代品

备注:

  1. 为什么我们需要这个永远正确的概念 Any?简单地说 template <template <typename> typename> 有什么问题?好吧,那是因为一个特殊的规则:如果参数完全没有约束,参数的约束将被忽略,一切正常。
  2. 为什么要写Any<T> && std::same_as<T, char>;?来说明一个观点。实际规则不会评估约束的布尔值,而是将约束作为公式进行比较,其中原子约束作为变量,参见here。所以正式的原因是 S 有一个比 T 严格更大(包含方面)的原子约束集的合取。如果 S 具有相同或更小的集合,则它是合式的。如果两个集合不是按包含排序的,则两个模板都不是更专业的,并且没有匹配项。