[英]How to implement the generalized form of std::same_as (i.e. for more than two type parameters) that is agnostic to parameter order?
We know that the concept std::same_as
is agnostic to order (in other words, symmetric): std::same_as<T, U>
is equivalent to std::same_as<U, T>
( related question ).我们知道概念
std::same_as
与顺序无关(换句话说,对称): std::same_as<T, U>
等价于std::same_as<U, T>
(相关问题)。 In this question, I would like to implement something more general: template <typename... Types> concept same_are =...
that checks whether types in the pack Types
are equal to each other.在这个问题中,我想实现一些更通用的东西:
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;
}
(My intention here is to enumerate over every possible ordered pair of types in the pack) (我的目的是枚举包中每一个可能的有序类型对)
Unfortunately, this code would not compile , with the compiler complaining that the call to foo(int, int)
is ambiguous.不幸的是,这段代码无法编译,编译器抱怨对
foo(int, int)
的调用不明确。 I believe that it considers are_same<U, T>
and are_same<T, U>
as not equivalent.我相信它认为
are_same<U, T>
和are_same<T, U>
不等价。 I would like to know why the code fails how I can fix it (so that the compiler treats them as equivalent)?我想知道为什么代码失败了我该如何修复它(以便编译器将它们视为等效)?
From cppreference.com Constraint_normalization来自cppreference.com Constraint_normalization
The normal form of any other expression E is the atomic constraint whose expression is E and whose parameter mapping is the identity mapping.
任何其他表达式 E 的范式是原子约束,其表达式为 E,其参数映射为恒等映射。 This includes all fold expressions, even those folding over the && or ||
这包括所有折叠表达式,甚至那些折叠在 && 或 || 上的表达式。 operators.
运营商。
So所以
template <typename... Types>
concept are_same = (... && same_with_others<Types, Types...>);
is "atomic".是“原子的”。
So indeed are_same<U, T>
and are_same<T, U>
are not equivalent.所以确实
are_same<U, T>
和are_same<T, U>
是不等价的。
I don't see how to implement it:-(我不知道如何实现它:-(
The problem is, with this concept:问题是,有了这个概念:
template <typename T, typename... Others>
concept are_same = (... && std::same_as<T, Others>);
Is that the normalized form of this concept is... exactly that.这个概念的规范化形式是……就是这样。 We can't "unfold" this (there's nothing to do), and the current rules don't normalize through "parts" of a concept.
我们不能“展开”这个(无事可做),并且当前的规则不会通过概念的“部分”来规范化。
In other words, what you need for this to work is for your concept to normalize into:换句话说,要使其正常工作,您需要将您的概念规范化为:
... && (same-as-impl<T, U> && same-as-impl<U, T>)
into:进入:
... && (is_same_v<T, U> && is_same_v<U, T>)
And consider one fold-expression &&
constraint to subsume another fold-expression constraint &&
if its underlying constraint subsumes the other's underlying constraint.并考虑一个折叠表达式
&&
约束包含另一个折叠表达式约束&&
如果其基础约束包含另一个的基础约束。 If we had that rule, that would make your example work.如果我们有该规则,那将使您的示例有效。
It may be possible to add this in the future - but the concern around the subsumption rules is that we do not want to require compilers to go all out and implement a full SAT solver to check constraint subsumption.将来可能会添加这个 - 但围绕包含规则的问题是我们不希望编译器完全要求 go 并实现一个完整的 SAT 求解器来检查约束包含。 This one doesn't seem like it makes it that much more complicated (we'd really just add the
&&
and ||
rules through fold-expressions), but I really have no idea.这似乎并没有让它变得更复杂(我们实际上只是通过折叠表达式添加
&&
和||
规则),但我真的不知道。
Note however that even if we had this kind of fold-expression subsumption, are_same<T, U>
would still not subsume std::same_as<T, U>
.但是请注意,即使我们有这种折叠表达式包含,
are_same<T, U>
仍然不会包含std::same_as<T, U>
。 It would only subsume are_same<U, T>
.它只会包含
are_same<U, T>
。 I am not sure if this would even be possible.我不确定这是否可能。
churill is right.Using std::conjunction_v might be helpful. churill 是对的。使用 std::conjunction_v 可能会有所帮助。
template <typename T,typename... Types>
concept are_same = std::conjunction_v<std::same_as<T,Types>...>;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.