Eksperymentowałem z Curiously Recurring Template Pattern dla generycznego pojedynczego argumentu funktora i mam dwie implementacje: jedną za pomocą parametru szablonu szablonu, który działa i drugą, w której próbuję uzyskać dostęp do pochodna Functor :: wpisz w klasie interfejsu. W tym ostatnim przykładzie, kompilator (gcc 5.4.0) informujeBrak typu o nazwie "typ" w klasie pochodnej CTRP
błąd: nie typ nazwany 'typ' w 'struct Cube < double>'
template<class T, template<class> class Functor>
class FunctorInterface_1 {
private:
const Functor<T> &f_cref;
public:
FunctorInterface_1() : f_cref(static_cast<const Functor<T>&>(*this)) {}
T operator() (T val) const { return f_cref(val); }
}; // FunctorInterface_1 (works)
template<class Functor>
class FunctorInterface_2 {
private:
const Functor &f_cref;
public:
using Ftype = typename Functor::type;
FunctorInterface_2() : f_cref(static_cast<const Functor&>(*this)) {}
Ftype operator() (Ftype val) const { return f_cref(val); }
}; // FunctorInterface_2 (no type in Functor!)
I następnie spróbuj skompilować z T = double w głównej() z następujących dwóch klas:
template<class T>
struct Square : public FunctorInterface_1<T,Square> {
T operator()(T val) const { return val*val; }
}; // Square
template<class T>
struct Cube : public FunctorInterface_2<Cube<T>> {
using type = T;
T operator() (T val) const { return val*val*val; }
}; // Cube
Czy można zmodyfikować przykład FunctorInterface_2/Cube do pracy, czy jest konieczne, aby klasa interfejsu była szablonem na T jako w pierwszym przykładzie? Dzięki!
EDIT: Korzystanie z gcc -std = C++ 14, można uzyskać drugi przykład, aby skompilować i uruchomić za pomocą automatycznego powrotu i typy argumentów w FunctorInterface_1 :: operator(), jednak, jak rozumiem, auto argumentem typy nie są częścią standardu C++ 14.
EDIT 2: Cóż, czuję się trochę gruby. Właśnie zdałem sobie sprawę, że mogę szablon FunctorInterface_1 :: operator() na nowy parametr, jednak dla aplikacji, którą mam na myśli, bardzo chciałbym mojej klasy bazowej, aby móc uzyskać dostęp do typów zdefiniowanych w klasie pochodnej.
Jest to raczej wymyślna alternatywa dla dostarczania tego typu bezpośrednio jako parametr szablonu, tak jak w przypadku OP w jego pierwszej implementacji. I muszę wspomnieć, że jeśli typ jest przekazywany przez cechę, to wówczas klasa pochodna musi także wyodrębnić ją z cechy, czyli 'używając type = T;' powinno być 'using type = FunctorTraits> :: type;'. W przeciwnym razie taka implementacja jest naprawdę delikatna. –
VTT
Podejście Cech ma pewien wpływ na utrzymanie moich interfejsów w sposób agnostyczny, jednak wydaje się, że będzie to obciążać rozwój typów pochodnych. Aplikacja, którą mam na myśli, polega na złożonych operacjach na wektorach abstrakcyjnych, które będą miały jakiś typ OrdinalType do indeksowania i niektóre elementy typu dla danych zawartych w nim. Zajmuję się również badaniami nad czystymi cechami (a nie dziedziczeniem), ale badam zalety alternatyw dla wirtualnego dziedziczenia (z copius dynamic downcasting!), Które obecnie wdrożyliśmy. –
@VTT, podejście cech ma inne zalety. Na przykład. klasa Functor nie musi być szablonem klasy, tak jak w pierwszym podejściu stosowanym przez OP. Zgadzam się z drugą kwestią. Jednak PO może nawet go nie potrzebować. –