如何实现对参数顺序不可知的std::same_as的广义形式(即对于两个以上的类型参数)

How to implement the generalized form of std::same_as (i.e. for more than two type parameters) that is agnostic to parameter order?

本文关键字:于两个 类型参数 as 顺序 参数 不可知 何实现 same std 实现      更新时间:2023-10-16

背景

我们知道概念std::same_as是不可知序的(换句话说,对称的(:std::same_as<T, U>等价于std::same_as<U, T>(相关问题(。在这个问题中,我想实现一些更通用的东西:template <typename ... Types> concept same_are = ...,它检查包Types中的类型是否彼此相等。

我的尝试

#include <type_traits>
#include <iostream>
#include <concepts>
template <typename T, typename... Others>
concept same_with_others = (... && std::same_as<T, Others>);
template <typename... Types>
concept are_same = (... && same_with_others<Types, Types...>);
template< class T, class U> requires are_same<T, U>
void foo(T a, U b) {
std::cout << "Not integral" << std::endl;
}
// Note the order <U, T> is intentional
template< class T, class U> requires (are_same<U, T> && std::integral<T>)
void foo(T a, U b) {
std::cout << "Integral" << std::endl;
}
int main() {
foo(1, 2);
return 0;
}

(我的意图是列举包中每一对可能的有序类型(

不幸的是,此代码无法编译,编译器抱怨对foo(int, int)的调用不明确。我认为它认为are_same<U, T>are_same<T, U>是不等价的。我想知道为什么代码失败,我该如何修复它(以便编译器将它们视为等效代码(?

这个概念的问题是:

template <typename T, typename... Others>
concept are_same = (... && std::same_as<T, Others>);

这个概念的标准化形式…正是这样。我们不能"展开"这一点(没有什么可做的(,目前的规则也不能通过概念的"部分"来规范化。

换句话说,你需要的是让你的概念正常化为:

... && (same-as-impl<T, U> && same-as-impl<U, T>)

进入:

... && (is_same_v<T, U> && is_same_v<U, T>)

并考虑一个折叠表达式&&约束包含另一个折叠表达约束&&,如果它的底层约束包含了另一个的底层约束。如果我们有这个规则,你的例子就会奏效。

将来可能会添加这一点,但对包容规则的担忧是,我们不想要求编译器全力以赴,实现一个完整的SAT求解器来检查约束包容。这个似乎并没有让它变得那么复杂(我们实际上只是通过折叠表达式添加&&||规则(,但我真的不知道。

然而,请注意,即使我们有这种折叠表达式包含,are_same<T, U>仍然不会包含std::same_as<T, U>。它只包含are_same<U, T>。我甚至不确定这是否可能。

来自cppreference.com Constraint_normalization

任何其他表达式E的范式都是原子约束,其表达式为E,其参数映射为单位映射。这包括所有的折叠表达式,甚至那些折叠在&amp;或||运算符。

所以

template <typename... Types>
concept are_same = (... && same_with_others<Types, Types...>);

是"原子"。

因此CCD_ 16和CCD_。

我不知道如何实现它:-(

churill是对的。使用std::concurrent_v可能会有所帮助。

template <typename T,typename... Types>
concept are_same = std::conjunction_v<std::same_as<T,Types>...>;