Andoza ixtisoslashuvi va merosga oid yaxshi amaliyotlar

Andoza bo'yicha ixtisoslashuv meros ierarxiyasini hisobga olmaydi. Masalan, agar Base uchun shablonni ixtisoslashtirsam va uni Derived bilan tuzadigan bo'lsangiz, mutaxassislik tanlanmaydi (quyida kodni ko'ring (1)).

Bu katta to'siq bo'lishi mumkin, chunki u ba'zida Liskovni tiklash printsipining buzilishiga olib keladi. Masalan, bu savol ustida ishlayotganda, Boost.Range algoritmlarini std: : sub_match bo'lsa, std :: pair . sub_match kodi pair dan ochiqdan beri egallab, pair har bir joyda sub_match , lekin bu shablon ixtisoslashuvidan foydalangan holda trait sinflari tufayli bajarilmaydi.

enable_if va is_base_of bilan bir qatorda qisman shablonni ixtisoslashuvi yordamida bu masalani engib o'tishimiz mumkin (kodni ko'rib chiqing (2)). Men bu echimni, ayniqsa, kutubxona kodini yozishda to'liq ixtisoslashuvdan afzal ko'ramanmi? Men ushbu yondashuvni nazorat qiladigan biron kamchiliklar bormi? Siz tez-tez foydalanadigan yoki ko'rgan amaliyotingizmi?


Namuna kodlari

(1)
#include 

struct Base {};
struct Derived : public Base {};

template < typename T >
struct Foo
{
    static void f() { std::cout << "Default" << std::endl; }
};

template <>
struct Foo< Base >
{
    static void f() { std::cout << "Base" << std::endl; }
};

int main()
{
    Foo::f();//prints "Default"
}

(2)
#include 
#include 

struct Base {};
struct Derived : public Base {};

template 
struct Foo
{
    static void f() { std::cout << "Default" << std::endl; }
};

template 
struct Foo<
    T, typename 
    std::enable_if< std::is_base_of< Base, T >::value >::type
>
{
    static void f() { std::cout << "Base" << std::endl; }
};

int main()
{
    Foo::f();//prints "Base"
}
23
+1. Ajoyib savol.
qo'shib qo'ydi muallif Nawaz, manba
+1 mukammal savol va motivatsiya.
qo'shib qo'ydi muallif sehe, manba

1 javoblar

enable_if is more flexible

Menimcha, activ_if yondashuvini chindan ham yoqtirishingiz kerak: bu siz talab qiladigan va ko'proq narsalarga imkon beradi.

Masalan, Derivativ sinfi Liskov-Base-for-Subsitutable deb nomlangan holatlar mavjud bo'lishi mumkin, ammo siz bunday funktsiyalarning/mutaxassisliklarning amal qilishlari uchun sizni qabul qilmoqchi emassiz/(masalan, Base POD klassi bo'lgani uchun) , shuning uchun Derived va POD bo'lmagan xatti-harakatlar yoki sinfga xos kompozitsiyaga nisbatan mutlaqo diktaturaga o'xshash narsalar).

enable_if gives you the power to define exactly the conditions.

Gibrid yondoshuv

Siz umumiy xususiyatlarga ega bo'lgan ba'zi xususiyatlarga ega bo'lgan xususiyatlarga ega bo'lgan belgilar sinfini qo'llash orqali ba'zi bir o'rta maydonlarga ham ega bo'lishingiz mumkin. "Maxsus" belgilar sizning istaklaringiz bilan xususiyatlarni polimorfik sifatida qo'llash uchun enable_if va meta-dasturlash texnikasidan foydalanishi mumkin. Shunday qilib, haqiqiy ilovalar ba'zi murakkab enable_if/dispatch raqsini takrorlash shart emas, lekin buning o'rniga oddiy belgilar sinfini (murakkablikni yashiradi) iste'mol qilishi mumkin.

I think some (many?) Boost libraries use the Gibrid yondoshuv (I've seen it in some capacity where it bridges e.g. fusion/mpl, I think also various iterator traits in Spirit).

Shaxsan men ushbu yondashuvni yaxshi ko'raman, chunki u "sanitariya-tesisat" ni kutubxonaning asosiy ishlaridan samarali ravishda xavfsiz holatga keltirib, va hujjatlarni (!)

13
qo'shib qo'ydi
@xayd: masalan. mytitr kabi bir narsani afzal qilasiz :: eligible_for_this_specialization :: std :: enable_if :: value> :: turi?
qo'shib qo'ydi muallif user396672, manba
@ user396672: Yo'q, men faollashtirishni xohlamayman va to'g'ridan-to'g'ri mytraits dan foydalaning. Siz maxsus xususiyatlar sinflaringizdagi shartlarni (ehtimol, enable_if ga asoslangan holda) yashirishingiz mumkin.
qo'shib qo'ydi muallif sehe, manba
Menimcha, kutubxona dizaynerlari kutubxonaning barcha imkoniyati cheklangan foydalanuvchilari uchun oldindan qaror qabul qila olmaydi. ( std :: pair ) oralig'idagi belgilarga o'xshash chegara holatlari mavjud bo'lishi mumkin, ammo umuman olganda, kutubxona dizaynerlari, masalan, - bu std :: juft <...> kerak
qo'shib qo'ydi muallif sehe, manba
@ user396672: Bularning barchasi haqida o'ylashning bir usuli shablonni moslash mumkin bo'lgan kancalarni ta'minlash uchun yo'nalishli sinflarni ishlatadigan "Template Method" (dizayn naqsh) sifatida ko'rishdir. Agar bazaviy shablonning ba'zi qismlarini sozlash kerak bo'lsa, u faqat tegishli xususiyatlarni ("bekor") bilishi kerak. Agar butun tuzilish/xatti o'zgarishi kerak bo'lsa, unda bazaviy shablonni ("bekor") ixtisoslashtirishi mumkin.
qo'shib qo'ydi muallif Luc Touraille, manba
Menimcha, ixtisoslikka tortilishi mumkin bo'lgan barcha narsalarni (bu polimorfik ravishda ixtisoslashtirilgan) xususiyatlarga aylantirish va foydalanuvchilarga taglik shablonini emas, balki xususiyatlarni o'rganishga rag'batlantirish yaxshi dasturdir (shablon usuli odatda virtual emas ).
qo'shib qo'ydi muallif Luc Touraille, manba
Foydalanuvchilarning qulayligi uchun, kutubxona tomonidan taqdim etilgan xususiyatlar, ehtimol polimorfik bo'lishi kerak.
qo'shib qo'ydi muallif Luc Touraille, manba
Boost.Rangeni ishlab chiquvchilarni ayblamayman, std :: pair har doim ham paydo bo'lishi kerak emas :).
qo'shib qo'ydi muallif Luc Touraille, manba