Turdagi turkumlarning bir to'plamining boshqasining quyi to'plami ekanligini tekshiring

Bitta parametr to'plami (to'siq sifatida tarjima qilingan) boshqasining quyi to'plamidirmi?

Hozirgacha faqat std :: tuple yordamida ishlaydigan ramkaga ega emasman, lekin hech qanday funksionallik mavjud emas.

#include 
#include 

template 
struct is_subset_of : std::false_type
{
};

template 
struct is_subset_of, std::tuple>
    : std::true_type
{
   //Should only be true_type if Types1 is a subset of Types2
};

int main() {
    using t1 = std::tuple;
    using t2 = std::tuple;
    using t3 = std::tuple;

    static_assert(is_subset_of::value, "err");
    static_assert(is_subset_of::value, "err");
    static_assert(is_subset_of::value, "err");
    static_assert(is_subset_of::value, "err");
    static_assert(!is_subset_of::value, "err");
}

Har bir turdagi to'plamda bir martadan ko'proq sodir bo'lishiga yo'l qo'yilmaydi.

Agar echim C ++ 11 bilan ishlayotgan bo'lsa yaxshi bo'lar edi.

16
Men oldin shunga o'xshash savolni oldim, ammo hozirda men kodimni tenglik tekshiruvidan pastki tekshirishga o'zgartiring.
qo'shib qo'ydi muallif Tobias Hermann, manba

9 javoblar

#include 
#include 

template 
constexpr bool contains = (std::is_same{} || ...);

template 
constexpr bool is_subset_of = false;

template 
constexpr bool is_subset_of, std::tuple>
           = (contains && ...);

DEMO

20
qo'shib qo'ydi
Recursionisiz o'z ichiga oladi ; o'z ichiga oladi = std :: is_same :: qiymati || is_subset_of bo'lmasdan yozing. Biroq, men yoza olaman deb o'ylamayman, "takomillashgan substansiya ketma-ketligi".
qo'shib qo'ydi muallif Yakk - Adam Nevraumont, manba
@PiotrSkotnicki Men buni bir ifodada qilish imkoniyatiga ega emasligim noto'g'ri edi; kengaytirish uchun paketlarni tanlash uchun ... ning etishmovchiligini bilishim mumkin emas (balki o'zaro o'xshashlik yoki boshqa narsalar kabi o'zaro o'xshashmi?)
qo'shib qo'ydi muallif Yakk - Adam Nevraumont, manba
Maslahat uchun rahmat
qo'shib qo'ydi muallif Piotr Skotnicki, manba
Buni faqat C ++-dan 17 tagacha ishlashini qo'shishingiz mumkin. Lekin, bu juda ham oqlangan, bir yechim!
qo'shib qo'ydi muallif Maarten Bamelis, manba

Agar C ++ 17 xususiyatidan foydalansangiz, Piotr Skotnicki ning echimini ishlatishni tavsiya qilaman!

Bir vaqtlar bu funksiyani amalga oshirishim kerak edi. Men shu nuqtada men bilan kelgan kodni nusxa ko'chirishga majbur qilaman.

Men bunday tekshirishni amalga oshirishning eng yaxshi yoki eng oqilona usuli deb da'vo qilmayman! Men chekka holatlar haqida juda ko'p o'ylashdan bezovta bo'lmadim; sizning talablaringizga mos keladigan kodni moslashtirishingiz kerak bo'lishi mumkin.

To clarify: ContainsTypes checks if Rhs is a subset of Lhs.


  template 
  struct ContainsType;

  template 
  struct ContainsType, U>
  {
      static const bool VALUE = ContainsType, U>::VALUE;
  };

  template 
  struct ContainsType, T>
  {
      static const bool VALUE = true;
  };

  template 
  struct ContainsType, T>
  {
      static const bool VALUE = false;
  };

 //-----

  template 
  struct ContainsTypes;

  template 
  struct ContainsTypes>
  {
      static const bool VALUE = ContainsType::VALUE && ContainsTypes>::VALUE;
  };

  template 
  struct ContainsTypes<>>
  {
      static const bool VALUE = true;
  };
7
qo'shib qo'ydi
qo'shib qo'ydi muallif Tobias Hermann, manba
Agar faqat bitta turdagi ro'yxatda bir martadan ortiq bo'lmasa, faqatgina ish.
qo'shib qo'ydi muallif Oliv, manba
@MaartenBamelis Siz bu to'g'ringizda, bu parametr paketining elementlari nimani anglatadi? shablon argumentlari ro'yxatining turini almashtirganingizda, ikkita shablonning mutanosibligini hisobga olib, shablon nuqtai nazaridan, parametr to'plami element_pozitsiyasini tartibga solish bilan bog'liq bo'lgan toifadagi xarita bo'lib, bu erda element_pozitsiyasi tartiblangan vosita hisoblanadi. Shunday qilib, parametr to'plamining bir to'plamini o'qiganimda, parametr to'plami mutlaqo to'siq bo'lmasa, savolga bir qancha qarama-qarshi javoblarni tan olaman deb o'ylayman.
qo'shib qo'ydi muallif Oliv, manba
@TobiasHermann Kodni noqonuniy nusxa ko'chirishga majbur qilaman. Sizning kodingiz bilan ishlash uchun olganingizni eshitishdan xursandman. Bundan tashqari, Piotr Skotnicki tomonidan berilgan javobga ishonch hosil qiling. Men sizga C ++ ning 17 xususiyatidan foydalanishingiz mumkin bo'lgan eng oqilona echimni topsam bo'ladi.
qo'shib qo'ydi muallif Maarten Bamelis, manba
Yaxshi ovlash! Ikki nusxani o'z ichiga olmaydi (bir xil ob'ektlar to'plamidir) uchun to'siq ni qabul qildim. Biroq, bu sizning ehtiyojlaringizga mos kelmasligi mumkin. Bundan tashqari, men tekshiruvdan oldin har ikkala argumentga tatbiq qilgan std :: tuple dan ikki nusxadagi turlarni olib tashlash uchun ba'zi tuzlarni yozdim.
qo'shib qo'ydi muallif Maarten Bamelis, manba

Menimcha, C ++ 17 javobingiz Piotrning javobiga qaraganda ancha soddadir »:

template 
struct contains : std::disjunction...>{};

template 
struct is_subset_of : std::false_type{};

template 
struct is_subset_of, std::tuple> : std::conjunction...> {};
Namoyish

disjunction and conjunction are new type traits introduced in C++17. We can take advantage of these to check if at least one type in the second tuple matches "the next type" in the first tuple, which we use parameter pack expansion extensively for.

4
qo'shib qo'ydi

Buni quyidagi kabi sinf bilan qilishingiz mumkin:

template
struct Check {
    template
    static constexpr bool verify() {
        using accumulator_type = bool[];
        bool check = false;
        accumulator_type accumulator = { (check = check || std::is_same())... };
        (void)accumulator;
        return check;
    }

    template
    static constexpr bool contain() {
        using accumulator_type = bool[];
        bool check = true;
        accumulator_type accumulator = { (check = check && verify())... };
        (void)accumulator;
        return check;
    }
};

Funktsiyaga asoslangan misolda uni to'g'irlash juda oson Bu sizning kodingizga moslashtirilgan mumkin bo'lgan ilovani ta'qib etadi:

#include 
#include 

template
struct Check {
    template
    static constexpr bool verify() {
        using accumulator_type = bool[];
        bool check = false;
        accumulator_type accumulator = { (check = check || std::is_same())... };
        (void)accumulator;
        return check;
    }

    template
    static constexpr bool contain() {
        using accumulator_type = bool[];
        bool check = true;
        accumulator_type accumulator = { (check = check && verify())... };
        (void)accumulator;
        return check;
    }
};


template 
struct is_subset_of;

template 
struct is_subset_of, std::tuple> {
    static constexpr bool value = Check::template contain();
};

int main() {
    using t1 = std::tuple;
    using t2 = std::tuple;
    using t3 = std::tuple;

    static_assert(is_subset_of::value, "err");
    static_assert(is_subset_of::value, "err");
    static_assert(is_subset_of::value, "err");
    static_assert(is_subset_of::value, "err");
    static_assert(!is_subset_of::value, "err");
}

Ish Check sinfida amalga oshiriladi va o'z ichiga oladi va confirm . o'z ichiga olgan a'zo funktsiyasi kirish nuqtasidir. Umumiy qavatni (katlama ifodalarini kutayotib) quyi to'plamni ochish uchun ishlatadi va har bir tarkib uchun aniq tekshirishni talab qiladi. verify funktsiyasi funktsiyasi, berilgan toifadagi yagona turni tanlab, qolganini qiladi.

Menga qo'shimcha ma'lumot bera olsam, yoki u qanchalik aniq bo'lsa, menga xabar bering.


Uni Coliru ustida ishlayotganini ko'ring.

3
qo'shib qo'ydi
constexpr bool any_of() { return false; }
template
constexpr bool any_of( bool b, Bools... bools ) {
  return b || any_of(bools...);
}
constexpr bool all_of() { return true; }
template
constexpr bool all_of( bool b, Bools...bools ) {
  return b && all_of(bools...);
}
template
struct contains_t : std::integral_constant::value... )
> {};

template
struct tuple_subset_of;

template
struct tuple_subset_of< std::tuple, std::tuple >:
  std::integral_constant::value... )
  >
{};

Live example.

Buning uchun C ++ 17 kodini osonlik bilan yaxshilashga mo'ljallangan. Buning uchun any_of va all_of yineluvchi ilovalarni katlayotganda o'zgartiring.

3
qo'shib qo'ydi

std :: is_base_of dan foydalangan holda, faqat qiziqarli bo'lganingiz uchun emas, balki (C ++ 14 da hech bo'lmaganda) constexpr funksiyasini yaratishingiz mumkin struct kabi.

Quyida ishlaydigan misol (faqat C ++ 14)

#include 
#include 
#include 

template 
struct foo : std::tuple...
 { };

template 
bool isSubsetOf (std::tuple const &, std::tuple const &)
 {
   bool ret { true };

   using un = int[];
   using d2 = foo;

   (void)un { (ret &= std::is_base_of, d2>::value, 0)... };

   return ret;
 }


int main()
 {
    using t1 = std::tuple;
    using t2 = std::tuple;
    using t3 = std::tuple;

    std::cout << isSubsetOf(t1{}, t1{}) << std::endl; //print 1
    std::cout << isSubsetOf(t1{}, t2{}) << std::endl; //print 1
    std::cout << isSubsetOf(t2{}, t1{}) << std::endl; //print 1
    std::cout << isSubsetOf(t1{}, t3{}) << std::endl; //print 1
    std::cout << isSubsetOf(t3{}, t1{}) << std::endl; //print 0
 }
3
qo'shib qo'ydi

is_subset_of version of an answer from your previous question:

#include 
#include 

template 
struct tag { };

template 
struct is_subset_of_helper: tag... { };

template 
struct is_subset_of: std::false_type { };

template 
struct bool_pack { };

template 
using my_and = std::is_same, bool_pack<true, Bs...>>;

template 
struct is_subset_of, std::tuple, typename std::enable_if< my_and< std::is_base_of, is_subset_of_helper>::value...  >::value  >::type  >:
   std::true_type { };

int main() {    
    using t1 = std::tuple;
    using t2 = std::tuple;
    using t3 = std::tuple;

    static_assert(is_subset_of::value, "err");
    static_assert(is_subset_of::value, "err");
    static_assert(is_subset_of::value, "err");
    static_assert(is_subset_of::value, "err");
    static_assert(!is_subset_of::value, "err");
}

[jonli demo]

2
qo'shib qo'ydi

Men shlyapamni ringga tashlayman deb o'ylayman. Bu C ++ 11 yechimi OP so'ragan kabi, C ++ 17 ning juda yaxshi xususiyatlari borligini tushunaman. O'zining ichki kodi bo'lgan static const bool yoki shunga o'xshash faqatgina true_type va false_type bool )

Salbiy tomoni shundaki, ushbu echim meni logical_or va logical_and ni amalga oshirishga majbur qildi, biz C ++ 17 da va disjunction shaklida bepul).

Mo''jizaviy kod

Maartan Barnelisning echimi ga qaraganda qisqartirilgan, lekin kamroq o'qilishi mumkin

namespace detail
{
template
struct logical_or : std::true_type{};

template<>
struct logical_or : std::false_type{};

template
struct logical_and : std::false_type{};

template<>
struct logical_and : std::true_type{};
}

template
struct contains : std::false_type{};

template
struct contains : std::true_type{};

template
struct contains : detail::logical_or::type, typename contains::type>{};

template
struct is_subset_of : std::false_type{};

template
struct is_subset_of, std::tuple> : contains{};

template
struct is_subset_of, std::tuple> : detail::logical_and::type, typename is_subset_of, std::tuple>::type>{};

Namoyish

2
qo'shib qo'ydi

Skypjack ko'rsatgan (shukr!) Hiyla ishlatgan holda, ContainsType va ContainsTypes uchun rekursiyadan qochishingiz mumkin.

Quyidagi misol (faqatgina std :: tuple s bilan emas, balki umumiy (shuningdek, turli xil) konteynerlarda ham ishlaydi).

#include 
#include 

template 
struct cType
{
    static const bool value {
        ! std::is_same::value...>,
                       std::integer_sequence::value..., false>>::value };
 };

template 
struct isSubsetOf : std::false_type
 { };

template 
2
qo'shib qo'ydi
Xush kelibsiz, lekin skypjack, Skypjack emas! :-)
qo'shib qo'ydi muallif skypjack, manba
@skypjack - Boshqalarning nomlarini katta harflar bilan boshlash yomon odatim bor. Uzr :-(
qo'shib qo'ydi muallif max66, manba