背景
我们知道这个概念std::same_as
与订单无关(换句话说,对称):std::same_as<T, U>
相当于 std::same_as<U, T>
( related question )。在这个问题中,我想实现一些更一般的东西: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;
}
(我的目的是枚举包中每个可能的有序类型对)
不幸的是,这个代码would not compile , 编译器提示调用
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>
.我不确定这是否可能。
关于c++ - 如何实现与参数顺序无关的 std::same_as 的广义形式(即对于两个以上的类型参数)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58724459/