Bir kavramın bir işleve aktarılması


12

Kavramlar derleme zamanı tahminleri olarak tanımlandığından, bu tahminleri derleme zamanı algoritmaları için yeniden kullanmak da mümkün müdür? Örneğin, bir demet içindeki tüm tiplerin bir konsepte uygun olup olmadığını kontrol etmek mümkün müdür? Gördüğüm kadarıyla, bir kavramı bir işleve herhangi bir şekilde aktarmak mümkün değil, bu da beni bu durumlar için şablonlar kullanmaya geri götürüyor.

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

Ne yapmak istiyorum böyle bir şey, bu yüzden kullanmak için her zaman kavramı sarmak zorunda değilim:

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

Buna yaklaşmanın bir yolu var mı?


Ve sonra kavram kavramları eklemek için bir teklif olacak ... BTW, all_types()kat ifadeleri kullanılarak önemli ölçüde basitleştirilebilir ... &&:return (... && Predicate::template test<Ts>());
Evg

@Evg harika olurdu :)
Igor R.

Yanıtlar:


5

Buna yaklaşmanın bir yolu var mı?

Şey, hayır, pek değil. C ++ 20'de değil. Günümüzde, bir dil kavramı-parametresi ile ilgili bir kavram yoktur. Değişken şablonlar bile şablon parametresi olarak kullanılamaz. Bu nedenle, bir konseptiniz varsa, sarmaktan kaçınamayız.

Ama yapabileceğimiz daha basit ambalajlar yazmak. Eğer "eski stil" tipi özellikleri tahmin olarak, özellikle std::integral_constants gibi davrananları kullanmayı kabul edersek, kendimizi tahmin olarak kullanılabilecek oldukça kısa "konsept" tanımlarına sahip olabiliriz.

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

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

Sanki iyi olarak var alabileceği bildiğim kadarıyla gördüğünüz gibi.


Bu, genel bir lambda'yı şablon şablonu olarak herhangi bir şekilde çözerek işe yarar mı? Bir lambda asla bir şablon değil gibi görünüyor, sadece çağrı operatörü?
Andreas Loanjoe

@AndreasLoanjoe - Gerçekten. Bir lambda asla bir şablon değildir. Ancak lambdaları etrafta geçirmek istiyorsanız, C ++ 20 bunu yapmanıza izin verir. Birkaç dakika içinde bunun bir varyantını ekleyebilirim.
StoryTeller - Unslander Monica

@AndreasLoanjoe - İkinci düşüncede, bir lambda hala çok ayrıntılı çıkıyor. Bunun harika bir alternatif olduğunu düşünmüyorum. İşte yine de godbolt.org/z/QSHy8X
StoryTeller - Unslander Monica

Umarım daha iyi bir şey eklerler :), ama evet bu cevap gibi görünüyor, sadece stil tipi özellikler bu işlevsellik kavramları sunmuyor (henüz).
Andreas Loanjoe

0

Hedefiniz "bir gruptaki tüm türlerin bir konsepte uygun olup olmadığını kontrol etmek" ise , bunun gibi bir şey yapabilirsiniz:

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

}

CANLI DEMO


AllSameVaryasyonunuz neden ? Bir tip kısıtlaması tarafından sunulan bir paketteki her şablon parametresi zaten ayrı olarak kısıtlanmıştır.
Davis Herring

@DavisHerring Anlamıyorum. Yani kavramın kendisi mi yoksa şablon parametreleri *_foo()mi?
kanstar

Ben işleri var kodu kaldırırsanız anlamına ...üzerinde Tsve&& ... bunu kullandığı. (Açıkçası isim AllSameo zaman uygunsuz olurdu, ama neden bir sayı olarak <int,int,int>zaten tek başına bir sayı ifade etmek istediğimden emin değilim .)
Davis Herring

@DavisHerring O zaman kavram olmaz AllSameama SameAs(bkz. en.cppreference.com/w/cpp/concepts/same_as ) ve OP şablon parametrelerinin variadic sayıda alan bir kavram olmasını istedik.
kanstar

Açıkçası std::same_as . Varyasyon kısmının önemli olduğunu düşünmüyorum: kavramın (istenen) değişken kimliği idi. Demek istediğim, konsept örneğinizin varyasyon yönünün kullanımı ile ilgisiz olmasıydı (varyasyon dışı kavramlar zaten şablon parametre paketleriyle çalışmaktadır).
Davis Herring
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.