Antecedentes
Sabemos que el concepto std::same_as
es agnóstico al orden (en otras palabras, simétrico): std::same_as<T, U>
es equivalente a std::same_as<U, T>
( pregunta relacionada ). En esta pregunta, me gustaría implementar algo más general: template <typename ... Types> concept same_are = ...
que verifique si los tipos en el paquete Types
son iguales entre sí.
Mi intento
#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;
}
(Mi intención aquí es enumerar todos los pares de tipos ordenados posibles en el paquete)
Desafortunadamente, este código no se compilaría , ya que el compilador se queja de que la llamada a foo(int, int)
es ambigua. Creo que lo considera are_same<U, T>
y are_same<T, U>
como no equivalente. Me gustaría saber por qué el código falla y cómo puedo solucionarlo (para que el compilador los trate como equivalentes).
fuente
same_with_others
en cada permutación posible de los tipos.... Types
son iguales? Tal vez std :: conjunción pueda ayudarte. Hay un ejemplo en la parte inferior de la página que parece similar a su enfoque.Respuestas:
El problema es, con este concepto:
Es que la forma normalizada de este concepto es ... exactamente eso. No podemos "desplegar" esto (no hay nada que hacer), y las reglas actuales no se normalizan a través de "partes" de un concepto.
En otras palabras, lo que necesita para que esto funcione es que su concepto se normalice en:
dentro:
Y considere una
&&
restricción de expresión de pliegue para subsumir otra restricción de expresión de pliegue&&
si su restricción subyacente subsume la restricción subyacente del otro. Si tuviéramos esa regla, eso haría que tu ejemplo funcionara.Es posible agregar esto en el futuro, pero la preocupación en torno a las reglas de subsunción es que no queremos exigir que los compiladores hagan todo lo posible e implementen un solucionador SAT completo para verificar la subsunción de restricciones. Este no parece que lo haga mucho más complicado (realmente solo agregaríamos las reglas
&&
y||
mediante expresiones de pliegue), pero realmente no tengo idea.Sin embargo, tenga en cuenta que incluso si tuviéramos este tipo de subsunción de expresión doble,
are_same<T, U>
aún no subsumiríastd::same_as<T, U>
. Solo subsumiríaare_same<U, T>
. No estoy seguro de si esto sería posible.fuente
(... && C<T>)
no subsumir el conceptoC<T>
sorprendería a muchos usuarios.((fold1<Ts> && ...) && (fold2<Ts> &&...))
como conjunción de(fold1<Ts> && ...)
y(fold2<Ts> && ...)
mientras que es atómica.De cppreference.com Restricción_normalización
Entonces
es "atómico"
De hecho,
are_same<U, T>
yare_same<T, U>
no son equivalentes.No veo cómo implementarlo :-(
fuente