Ein Konzept an eine Funktion übergeben

12

Ist es auch möglich, diese Prädikate für Algorithmen zur Kompilierungszeit wiederzuverwenden, da Konzepte als Prädikate zur Kompilierungszeit definiert sind? Wäre es beispielsweise möglich zu überprüfen, ob alle Typen in einem Tupel einem Konzept entsprechen? Soweit ich gesehen habe, ist es nicht möglich, ein Konzept in irgendeiner Weise an eine Funktion zu übergeben, was mich zurückführt, Vorlagen für diese Fälle zu verwenden.

#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>());
}

Was ich gerne machen würde, ist so etwas, also muss ich das Konzept nicht die ganze Zeit einpacken, um es verwenden zu können:

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>());
}

Gibt es eine Möglichkeit, dem näher zu kommen?

Andreas Loanjoe
quelle
Und dann wird es einen Vorschlag geben, Konzepte von Konzepten hinzuzufügen ... Übrigens, all_types()kann mit Fold-Ausdrücken erheblich vereinfacht werden ... &&:return (... && Predicate::template test<Ts>());
Evg
@ Evg es wäre toll :)
Igor R.

Antworten:

5

Gibt es eine Möglichkeit, dem näher zu kommen?

Nein, nicht wirklich. Nicht in C ++ 20. In der heutigen Sprache gibt es keinen Begriff für einen Vorlagenkonzeptparameter. Auch variable Vorlagen können nicht als Vorlagenparameter verwendet werden. Wenn Sie also zunächst ein Konzept haben, können wir das Umwickeln nicht vermeiden.

Wir können jedoch einfachere Wrapper schreiben. Wenn wir uns damit einverstanden erklären, Merkmale vom Typ "alter Stil" als Prädikate zu verwenden, insbesondere solche, die sich wie std::integral_constants verhalten , können wir ziemlich knappe "Konzept" -Definitionen haben, die als Prädikate verwendet werden können.

template<typename T>
using FloatLike = std::is_same<T, float>;

template<template <typename> class Predicate, typename... T>
constexpr bool all_types()
{
    return (Predicate<T>{} && ...);
}

Es ist so gut wie es nur geht , soweit ich sehen kann.

Geschichtenerzähler - Unslander Monica
quelle
Würde dies funktionieren, indem ein generisches Lambda in irgendeiner Weise als Vorlagenvorlage deklariert wird? Es scheint, als wäre ein Lambda niemals eine Vorlage, aber nur der Anrufer?
Andreas Loanjoe
@AndreasLoanjoe - In der Tat. Ein Lambda ist niemals eine Vorlage. Wenn Sie jedoch bereit sind, Lambdas weiterzugeben, können Sie dies mit C ++ 20 tun. Ich kann in wenigen Minuten eine Variante davon hinzufügen.
Geschichtenerzähler - Unslander Monica
@AndreasLoanjoe - Beim zweiten Gedanken kommt ein Lambda immer noch sehr ausführlich heraus. Ich denke nicht, dass es eine großartige Alternative ist. Hier ist es sowieso godbolt.org/z/QSHy8X
StoryTeller - Unslander Monica
Ich hoffe, sie werden etwas Besseres hinzufügen :), aber ja, es scheint, dass dies die Antwort ist, nur Stilmerkmale bieten diese Funktionskonzepte (noch) nicht.
Andreas Loanjoe
0

Wenn Ihr Ziel darin besteht, "zu überprüfen, ob alle Typen in einem Tupel einem Konzept entsprechen" , können Sie Folgendes tun:

// concept to check if all types in Ts are the same as T
template<typename T, typename... Ts>
concept AllSame = (std::is_same_v<T,Ts> && ...);

// function only accepts floats as template parameters
template<AllSame<float>... Floats>
constexpr void float_foo()
{
}

// function only accepts ints as template parameters
template<AllSame<int>... Ints>
constexpr void int_foo()
{
}

// function only accepts T as template parameters
template<typename T, AllSame<T>... Ts>
constexpr void foo()
{
}

int main()
{
    int_foo<int, int, int>();
    // int_foo<int, int, double>(); // fails to compile
    float_foo<float, float, float>();
    // float_foo<float, float, int>(); // fails to compile
    foo<int, int, int, int>();
    // foo<int, int, int, float>(); // fails to compile
    foo<double, double, double, double>();
    // foo<double, double, double, int>(); // fails to compile

}

LIVE DEMO

kanstar
quelle
Warum ist dein AllSameVariadic? Jeder Vorlagenparameter in einem Paket, der durch eine Typbeschränkung eingeführt wird , ist bereits separat eingeschränkt.
Davis Herring
@ DavidHerring Ich verstehe nicht. Meinen Sie das Konzept selbst oder die Vorlagenparameter in *_foo()?
Kanstar
Ich meine , dass der Code , den Sie funktioniert, wenn Sie das Entfernen ...auf Tsund die , && ...die es verwendet. (Natürlich wäre der Name AllSamedann unangemessen, aber ich bin mir nicht sicher, warum ich <int,int,int>sowieso eine Zählung in unär ausdrücken möchte .)
Davis Herring
@DavisHerring Dann wäre das Konzept nicht anders AllSameals SameAs(siehe en.cppreference.com/w/cpp/concepts/same_as ) und OP wollten ein Konzept, das eine unterschiedliche Anzahl von Vorlagenparametern akzeptiert.
Kanstar
Offensichtlich wäre es std::same_as. Ich glaube nicht, dass der variadische Teil der Punkt war: Es war die (gewünschte) variable Identität des Konzepts. Mein Punkt war, dass der variadische Aspekt Ihres Konzeptbeispiels für seine Verwendung irrelevant war (da nicht variadische Konzepte bereits mit Vorlagenparameterpaketen funktionieren).
Davis Herring