Alternatywą dla szablonów jest użycie zamknięcia lambda z C++ 11. Oto moje preferencje.
// in header file
IClass * MyFunctionThatDoesStuff(const IParams & interface_params,
std::function<IClass * (const IParams & interface_params)> cls_allocator);
// in source file
IClass * MyFunctionThatDoesStuff(const IParams & interface_params,
std::function<IClass * (const IParams & interface_params)> cls_allocator) {
// Some processing. Perhaps the interface_params are generated
// inside this function instead of being passed to it.
IClass * mCls = cls_allocator(interface_params);
// Do whatever with mCls
return mCls;
}
// Somewhere else in the code.
{
Param1Type param1 = whatever1;
Param2Type param1 = whatever2;
// param1, param2, etc. are parameters that only
// SomeClsDerivedFromIClass constructor knows about. The syntax ¶m1
// achieves the closure.
// interface_param1 is common to all classes derived from IClass.
// Could more than one parameter. These parameters are parameters that
// vary from different calls of MyFunctionThatDoesStuff in different
// places.
auto cls_allocator =
[¶m1, ¶m2](const IParams & interface_params)->IClass * {
return new SomeCls1DerivedFromIClass(interface_params,
param1, param2);
};
IClass * mCls = MyFunctionThatDoesStuff(interface_params,
cls_allocator);
}
// Somewhere else in the code again.
{
ParamXType paramX = whateverX;
ParamYType paramY = whateverY;
auto cls_allocator =
[¶mX, ¶mY](const IParams & interface_params)->IClass * {
return new SomeCls2DerivedFromIClass(interface_params,
paramX, paramY);
};
IClass * mCls = MyFunctionThatDoesStuff(interface_params,
cls_allocator);
}
Powyższy pomysł kodu działa dobrze w przypadku szybkiego wzorca budowania lub odmiany wzoru fabrycznego. Metoda lambda jest w zasadzie metodą fabryczną. Aby uczynić go jeszcze bardziej dynamicznym, możesz użyć auto do wpisywania parametrów. Coś takiego.
auto * MyFunctionThatDoesStuff(const auto & interface_params,
std::function<auto * (const auto & interface_params)> cls_allocator);
Przychodzę do tego z wpływu Pythona, w którym można po prostu przekazać typ klasy do funkcji.
@Martin, jest to interesująca definicja "stosunkowo nowego", biorąc pod uwagę, że Smalltalk, który był dość popularny w swoim czasie, i miał w nim sporo kodu, zrobił to właśnie w latach 70. :) –
Podobnie jak wiele innych rzeczy przypisane do Smalltalk, Lisp istniał tam w latach pięćdziesiątych - cały program był strukturą, którą można było sprawdzić i zmanipulować. –