Como os conceitos são definidos como predicados em tempo de compilação, também é possível realmente reutilizá-los para algoritmos em tempo de compilação? Por exemplo, seria possível verificar se todos os tipos em uma tupla estão em conformidade com um conceito? Até onde eu vi, não é possível passar um conceito para uma função de forma alguma, o que me leva a voltar a usar modelos para esses casos.
#include <type_traits>
template<typename T>
concept FloatLike = std::is_same_v<T, float>;
struct IsFloat
{
template<typename U>
constexpr static bool test()
{
return FloatLike<U>;
}
};
template<typename Predicate, typename... T>
constexpr bool all_types()
{
return (Predicate::template test<T>() && ...);
}
int main()
{
static_assert(all_types<IsFloat, float, float>());
static_assert(!all_types<IsFloat, float, int>());
}
O que eu gostaria de fazer é algo assim, então não preciso envolver o conceito o tempo todo para poder usá-lo:
template<concept Predicate, typename... T>
constexpr bool all_types()
{
return (Predicate<T> && ...);
}
int main()
{
static_assert(all_types<FloatLike, float, float>());
static_assert(!all_types<FloatLike, float, int>());
}
Existe alguma maneira de se aproximar disso?
all_types()
pode ser significativamente simplificado usando expressões de dobra... &&
:return (... && Predicate::template test<Ts>());
Respostas:
Bem, não, na verdade não. Não em C ++ 20. Atualmente, não há noção na linguagem de um parâmetro-conceito de modelo. Mesmo modelos variáveis não podem ser usados como parâmetros de modelo. Portanto, se você tem um conceito para começar, não podemos evitar o acondicionamento.
Mas o que podemos fazer é escrever invólucros mais simples. Se concordarmos em usar traços do tipo "estilo antigo" como predicados, especificamente aqueles que se comportam como
std::integral_constant
s, podemos ter definições de "conceito" bastante concisas que podem ser usadas como predicados.É tão bom quanto possível , tanto quanto eu posso ver.
fonte
Se seu objetivo é "verificar se todos os tipos em uma tupla estão em conformidade com um conceito" , você pode fazer algo assim:
DEMONSTRAÇÃO AO VIVO
fonte
AllSame
variável? Cada parâmetro de modelo em um pacote introduzido por uma restrição de tipo já está restrito separadamente.*_foo()
?...
onTs
e o&& ...
que o usa. (Obviamente o nomeAllSame
, então, seria inapropriado, mas eu não sei por que eu quero expressar uma contagem em unário como<int,int,int>
de qualquer maneira.)AllSame
masSameAs
(consulte en.cppreference.com/w/cpp/concepts/same_as ) e o OP queria ter um conceito que requer um número variado de parâmetros de modelo.std::same_as
. Eu não acho que a parte variável era o ponto: era a identidade variável (desejada) do conceito. E o que quero dizer é que o aspecto variável do seu exemplo de conceito é irrelevante para o seu uso (porque conceitos não-variáveis também funcionam com pacotes de parâmetros de modelo).