Належная практыка ў дачыненні да спецыялізацыі шаблону і ўспадкоўванне

Шаблон спецыялізацыя не ўлічвае іерархію кошт атрымання ў спадчыну. Напрыклад, калі я спецыялізуюцца шаблон для Base і стварыць яго асобнік з Derived , спецыялізацыя не будзе абраны (гл код (1) ніжэй).

Гэта можа быць сур'ёзнай перашкодай, таму што часам прыводзіць да парушэння прынцыпу замяшчэння Ліскі. Напрыклад, падчас працы на гэтае пытанне , я заўважыў, што я не мог выкарыстаць Boost.Range алгарытмы з станд: : sub_match у той час як я мог бы з станд :: пара . Так як sub_match спадчыну публічна ад пара , здаровы сэнс падказвае, што я мог бы замяніць sub_match ўсюды пара выкарыстоўваецца , але гэта не атрымоўваецца з-за чорт класаў з выкарыстаннем шаблону спецыялізацыі.

Мы можам вырашыць гэтую праблему з дапамогай частковай спецыялізацыі шаблону разам з enable_if і is_base_of (гл код (2)). Ці павінен я заўсёды на карысць гэтага рашэння па поўнай спецыялізацыі, асабліва пры напісанні кода бібліятэкі? Ці існуюць якія-небудзь недахопы гэтага падыходу, які я курыруемых? Гэта практыка, якая выкарыстоўваецца або бачылі часта выкарыстоўваецца?


прыклады кодаў

(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. Выдатны пытанне, на самай справе.
дададзена аўтар Nawaz, крыніца
+1 Выдатны пытанне і матывацыя.
дададзена аўтар sehe, крыніца

1 адказы

enable_if is more flexible

Я думаю, вы павінны сапраўды аддаюць перавагу enable_if падыход: ён дазваляе ўсё, што вы маглі б запатрабаваць і больш.

напрыклад там могуць быць выпадкі, калі вытворны клас Ліскі-Subsitutable для базы, але вы [не можаце выказаць здагадку,/DONOT хочаце ўжыць] тыя ж рысы/спецыялізацый, каб быць сапраўдным (напрыклад, таму што база з'яўляецца клас POD , тады як Вытворныя Ands паводзіны не-POD або somehting падобнае, якая цалкам артаганальнай да класа кампазіцыі).

enable_if gives you the power to define exactly the conditions.

гібрыдны падыход

Акрамя таго, можна дасягнуць пэўнага Middleground шляху рэалізацыі класа рысы, вытворны некаторых спецыфічных для прыкладання рысы ад прыкмет агульнага прызначэння. «Карыстальніцкі» рысы маглі б выкарыстоўваць enable_if і мэта-праграмавання метады, каб прымяніць рысы, як паліморфны, як вы хочаце. Такім чынам, фактычныя рэалізацыі не павінны паўтараць некаторыя складаныя enable_if/адпраўка танец, але замест таго, каб проста спажываць клас мытна-якасці (які хавае складанасць).

I think some (many?) Boost libraries use the гібрыдны падыход (I've seen it in some capacity where it bridges e.g. fusion/mpl, I think also various iterator traits in Spirit).

Асабіста мне падабаецца гэты падыход, паколькі ён можа эфектыўна ізаляваць «сантэхніку» ад асноўнага бізнесу бібліятэкі, робячы абслугоўванне і дакументацыя (!) Нашмат прасцей.

13
дададзена
@sehe: напрыклад, вы аддаеце перавагу нешта накшталт mytraits :: eligible_for_this_specialization :: увядзіце замест станд :: enable_if <�станд :: is_base_of :: значэнне> :: тыпу?
дададзена аўтар user396672, крыніца
@ User396672: не, я хацеў бы пазбегнуць enable_if наогул і выкарыстоўваць mytraits непасрэдна. Вы можаце «хаваць» умоўнымі (магчыма, на аснове enable_if ) усярэдзіне вас прыстасаваныя класы уласцівасцяў.
дададзена аўтар sehe, крыніца
Я думаю, што распрацоўшчыкі бібліятэкі не могуць вырашыць, што фронт для ўсіх магчымых карыстальнікаў бібліятэкі. (Там могуць быць памежныя выпадкі, як, напрыклад дыяпазонах рысы з станд :: пары <�Ён, яна> , але ў цэлым я лічу, што бібліятэчныя дызайнеры павінны быць вельмі кансерватыўнымі пры здагадцы, напрыклад, што любы клас, ёсць - станд :: пара <...> павінен таксама мадэляваць дыяпазон)
дададзена аўтар sehe, крыніца
Вельмі добры адказ, дзякуй. Я думаю, што гібрыдны падыход вы абуджаюцца можа быць звязаны з тэга дыспетчарскай : выкарыстоўваць паліморфны клас ўласцівасці, каб атрымаць пазнаку, а затым выкарыстоўваць спецыялізацыю або перагрузкі на аснове тэгаў (нават калі пазнакі могуць часам быць паліморфны, так што яны, магчыма, варта быць зарэзерваваны для перагрузкі ...).
дададзена аўтар Luc Touraille, крыніца
@ User396672: Адзін са спосабаў думаць пра ўсё гэта, каб паглядзець базавы шаблон як «Template Method» (шаблон праектавання), які выкарыстоўвае класы для забеспячэння чорт рэальнага наладжвальных гакаў. Калі трэба наладзіць некаторыя часткі базавай шаблону, яна проста павінна спецыялізавацца ( «перавызначыць») адпаведныя рысы. Калі ўся структура/паводзіны павінна быць зменена, то можна па-ранейшаму спецыялізуецца ( «перавызначыць») базавы шаблон.
дададзена аўтар Luc Touraille, крыніца
Я думаю, што добрая практыка будзе інкапсуляваць ўсё, што можа быць прадметам спецыялізацыі ў рысы (якія, магчыма, будуць спецыялізаваўся паліморфных), а таксама заахвочваць карыстальнікаў спецыялізавацца рысы, а не базавы шаблон (даволі шмат, як шаблонны метад, як правіла, не з'яўляецца віртуальным ).
дададзена аўтар Luc Touraille, крыніца
Для зручнасці карыстальніка, рыса спецыялізацыя ўжо прадстаўляецца бібліятэкай, верагодна, варта быць паліморфны, хоць.
дададзена аўтар Luc Touraille, крыніца
Я не вінавачу распрацоўшчыкаў Boost.Range, станд :: Пара не азначае быць атрыманы з так ці інакш :).
дададзена аўтар Luc Touraille, крыніца