コンセプトを関数に渡す


12

概念はコンパイル時の述語として定義されているため、これらの述語をコンパイル時のアルゴリズムに実際に再利用することもできますか?たとえば、タプルのすべての型がコンセプトに準拠しているかどうかを確認することは可能でしょうか?私が見た限りでは、概念を関数に渡すことは決して不可能であり、そのため、これらの場合にテンプレートを使用することに戻ってきました。

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

私がやりたいのは次のようなものなので、それを使用できるようにするために常にコンセプトをラップする必要はありません。

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

これに近づく方法はありますか?


そして、コンセプトのコンセプトを追加する提案があります...ところで、all_types()折りたたみ式を使用して大幅に簡略化できます... &&return (... && Predicate::template test<Ts>());
Evg

@Evg素晴らしい:)
Igor R.

回答:


5

これに近づく方法はありますか?

まあ、いや、そうでもない。C ++ 20にはありません。今日の言語では、テンプレートコンセプトパラメータの概念はありません。変数テンプレートでさえ、テンプレートパラメータとして使用できません。したがって、最初にコンセプトがある場合、ラッピングを回避することはできません。

しかし、私たちにできることは、より単純なラッパーを書くことです。「古いスタイル」タイプの特性を述語として使用することに同意する場合、特にstd::integral_constantsのように動作する特性は、述語として使用できるかなり簡潔な「概念」定義を持つことができます。

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

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

私が見る限り、それはできる限り良いです。


これは、一般的なラムダをテンプレートテンプレートとして何らかの方法でdecltypingすることで機能しますか?ラムダはテンプレートではありませんが、呼び出し演算子だけですか?
Andreas Loanjoe

@AndreasLoanjoe-確かに。ラムダは決してテンプレートではありません。しかし、ラムダを渡すことをいとわない場合は、C ++ 20を使用できます。そのバリエーションを数分で追加できます。
StoryTeller-Unslander Monica

@AndreasLoanjoe-考え直してみると、ラムダはまだ非常に冗長になります。それは素晴らしい選択肢ではないと思います。とにかくgodbolt.org/z/QSHy8X
StoryTeller-Unslander Monica

私は彼らがより良いものを追加することを願っています:)、しかしそれは答えであるようです、スタイルタイプの特性のみがこの機能の概念を提供しています(まだ)。
Andreas Loanjoe

0

「タプル内のすべての型がコンセプトに準拠しているかどうかを確認することが目標である場合は、次のようなことができます。

// 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

}

ライブデモ


なぜあなたはAllSame可変的ですか?タイプ制約によって導入されたパックの各テンプレートパラメータは、すでに個別に制約されています。
Davis Herring

@DavisHerringわかりません。コンセプトそのもの*_foo()ですか、それともテンプレートパラメータですか?
kanstar

つまり、...on Tsとそれ&& ...を使用するを削除すれば、使用しているコードは機能します。(当然、その名前AllSameは不適切ですが、<int,int,int>とにかくなぜ単項で数えたいのかわかりません。)
Davis Herring

@DavisHerringでは、コンセプトはそうではありませんAllSameSameAsen.cppreference.com/w/cpp/concepts/same_asを参照)、OPは可変数のテンプレートパラメータを取るコンセプトが必要でした。
kanstar

明らかにそうですstd::same_as。可変部分がポイントだったとは思いません。それはコンセプトの(望ましい)可変的なアイデンティティでした。そして、私の要点は、概念の例の可変部分はその使用とは無関係であるということでした(非可変概念は既にテンプレートパラメーターパックで機能するため)。
Davis Herring
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.