为什么不验证模板模板参数中的概念?
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 T
比 template <typename> struct S
更专业。粗略地说,template <Char>
接受了 template <typename>
接受的子集(“至少像专业化”实际意味着什么的确切定义相当复杂,但这是第零个近似值)。
这意味着实参可以在所有可以使用形参的上下文中使用。也就是说,对于 T<K>
有效的任何类型 K
,S<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
.
的有效替代品
备注:
- 为什么我们需要这个永远正确的概念
Any
?简单地说 template <template <typename> typename>
有什么问题?好吧,那是因为一个特殊的规则:如果参数完全没有约束,参数的约束将被忽略,一切正常。
- 为什么要写
Any<T> && std::same_as<T, char>;
?来说明一个观点。实际规则不会评估约束的布尔值,而是将约束作为公式进行比较,其中原子约束作为变量,参见here。所以正式的原因是 S
有一个比 T
严格更大(包含方面)的原子约束集的合取。如果 S
具有相同或更小的集合,则它是合式的。如果两个集合不是按包含排序的,则两个模板都不是更专业的,并且没有匹配项。
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 T
比 template <typename> struct S
更专业。粗略地说,template <Char>
接受了 template <typename>
接受的子集(“至少像专业化”实际意味着什么的确切定义相当复杂,但这是第零个近似值)。
这意味着实参可以在所有可以使用形参的上下文中使用。也就是说,对于 T<K>
有效的任何类型 K
,S<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
.
备注:
- 为什么我们需要这个永远正确的概念
Any
?简单地说template <template <typename> typename>
有什么问题?好吧,那是因为一个特殊的规则:如果参数完全没有约束,参数的约束将被忽略,一切正常。 - 为什么要写
Any<T> && std::same_as<T, char>;
?来说明一个观点。实际规则不会评估约束的布尔值,而是将约束作为公式进行比较,其中原子约束作为变量,参见here。所以正式的原因是S
有一个比T
严格更大(包含方面)的原子约束集的合取。如果S
具有相同或更小的集合,则它是合式的。如果两个集合不是按包含排序的,则两个模板都不是更专业的,并且没有匹配项。