fundo
Sabemos que o conceito std::same_as
é agnóstico em ordem (em outras palavras, simétrico): std::same_as<T, U>
é equivalente a std::same_as<U, T>
( questão relacionada ). Nesta pergunta, eu gostaria de implementar algo mais geral: template <typename ... Types> concept same_are = ...
que verifique se os tipos no pacote Types
são iguais entre si.
Minha tentativa
#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;
}
(Minha intenção aqui é enumerar todos os tipos possíveis de tipos ordenados no pacote)
Infelizmente, esse código não seria compilado , com o compilador reclamando que a chamada para foo(int, int)
é ambígua. Acredito que considere are_same<U, T>
e are_same<T, U>
como não equivalente. Gostaria de saber por que o código falha, como posso corrigi-lo (para que o compilador os trate como equivalentes)?
c++
c++20
c++-concepts
fold-expression
Rin Kaenbyou
fonte
fonte
same_with_others
em todas as permutações possíveis dos tipos.... Types
são iguais? Talvez std :: joint possa ajudá-lo. Há um exemplo na parte inferior da página que parece semelhante à sua abordagem.Respostas:
O problema é que, com este conceito:
É que a forma normalizada desse conceito é ... exatamente isso. Não podemos "desdobrar" isso (não há nada a fazer), e as regras atuais não se normalizam através das "partes" de um conceito.
Em outras palavras, o que você precisa para que isso funcione é que seu conceito se normalize em:
para dentro:
E considere uma
&&
restrição de expressão de dobra para incluir outra restrição de expressão de dobra&&
se sua restrição subjacente subsumir a restrição subjacente da outra. Se tivéssemos essa regra, isso faria o seu exemplo funcionar.Pode ser possível adicionar isso no futuro - mas a preocupação com as regras de subsunção é que não queremos exigir que os compiladores façam tudo e implementem um solucionador SAT completo para verificar a subsunção de restrição. Este não parece que o torna muito mais complicado (nós realmente adicionamos as regras
&&
e||
através de expressões de dobra), mas eu realmente não tenho ideia.Observe, no entanto, que mesmo se tivéssemos esse tipo de subsunção de expressão de dobra,
are_same<T, U>
ainda assim não haveria subsunçãostd::same_as<T, U>
. Seria apenas subsumirare_same<U, T>
. Não tenho certeza se isso seria possível.fonte
(... && C<T>)
não incluir o conceitoC<T>
surpreenderia muitos usuários.((fold1<Ts> && ...) && (fold2<Ts> &&...))
como conjunto de(fold1<Ts> && ...)
e(fold2<Ts> && ...)
considerando que é atômica.De cppreference.com Normalização de restrições
assim
é "atômico".
Então, de fato
are_same<U, T>
eare_same<T, U>
não são equivalentes.Não vejo como implementá-lo :-(
fonte