简体   繁体   English

如何实现与参数顺序无关的 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?

Background背景

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中的类型是否彼此相等。

My attempt我的尝试

#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.

相关问题 如何将OpenCV中的adaptiveThreshold用于大于255的值(即,类型CV_8UC1)? - How to use adaptiveThreshold from OpenCV for values larger than 255 (i.e. type CV_8UC1)? 如何定义一个类型与几种类型中的任何一种相同的 C++ 概念? - How to define a C++ concept that a type is same_as any one of several types? 为什么允许 std::variant 多次持有相同的类型? - why is std::variant permitted to hold the same type more than once? 为什么 same_as 概念会两次检查类型相等性? - Why does same_as concept check type equality twice? Doxygen:是否可以对C ++函数参数进行分组,即具有相同的文档而不重复它? - Doxygen: Is it possible to group C++ function parameters, i.e. have the same documentation without duplicating it? 如何将支持的类型添加到现有的遗留std :: list操作函数(即模板?) - How to add supported types to existing legacy std::list manipulation functions (i.e. templates?) C++ 17:如何使用参数包来明确function中参数的顺序,都是相同的类型 - C++ 17: How to use parameter packs to clarify the order of parameters in a function which all have the same type 如何构造带有嵌入值的 std::string,即“字符串插值”? - How to construct a std::string with embedded values, i.e. "string interpolation"? 我需要 std::conditional 但有两个以上的选择 - I need std::conditional but with more than two choices 是否存在不使用 null 终止符的类似于 std::string 的类型(即保存任意长度的数据块)? - Does there exist a type similar to std::string (i.e., holding blobs of data of arbitrary length) that does not use the null terminator?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM