I am trying to write a small library where I need to enforce a specific template specialization. Assume I have an abstract class Abstract<S,T>
with two template arguments. I also have another (abstract) class which is parameterized by Abstract<S,T>
as in Other<U, V, Abstract<S,T>>
. I would like to define virtual void Other<U, V, Abstract<S,T>>::operator()(U, V, Abstract<S,T>&) = 0;
so that yet another Another<S,T,U> : public Other<S,T,U>
(concrete) class can override
the operator()
for references to the abstract object. This way, I can create new types which can use the inheritance mechanism for any Concrete<S,T> : public Abstract<S,T>
object it receives in its operator()
.
I am not a great software architect. Below is a small code excerpt of how I think the above mechanism could be enforced. I have already read about the issue in different forums, and have realized that this might be solved using type_traits
of C++11
(maybe a SFINAE-type of solution, I don't know).
I would appreciate if you could give me an idea of how to enforce such a mechanism. Or, even better, another approach (i.e., a different design pattern solution) to my problem, if needed.
#include <iostream>
#include <type_traits>
template <typename S, typename T>
class Abstract {
public:
Abstract() { std::cout << "Abstract: ctor called." << std::endl; }
virtual void operator()(void) {
std::cout << "Abstract::operator() called." << std::endl;
}
};
template <typename S, typename T>
class Concrete : public Abstract <S, T> {
public:
Concrete() { std::cout << "Concrete: ctor called." << std::endl; }
void operator()(void) override {
std::cout << "Concrete::operator() called." << std::endl;
}
};
template <typename S, typename T>
class A {
public:
A() { std::cout << "A: ctor called." << std::endl; }
};
template < typename S, typename T, typename U >
class B {
// hopefully a catch-all static_assert to warn the user about the template
// specialization.
};
template < typename S, typename T, typename U, typename V >
class B < S, T, Abstract<U, V> > {
public:
B() { std::cout << "B: ctor called." << std::endl; }
virtual void operator()(S s, T t, Abstract<U,V>& y) {
std::cout << "B::operator(S, T, U&) called." << std::endl;
y();
};
};
template < typename S, typename T, typename U >
class C : public B < S, T, U > {
public:
C() { std::cout << "C: ctor called." << std::endl; }
void operator()(S s, T t, U& y) override {
std::cout << "C::operator(S, T, U&) called." << std::endl;
y();
};
};
int main (int argc, char* argv[]) {
// B <int, int, A<double, double>> b1 { };
B <int, int, Abstract<double, double>> b2 { };
// B <int, int, Concrete<double, double>> b3 { };
C <int, int, Abstract<double, double>> c1 { };
// A <double, double> obj1 { };
Concrete <double, double> obj2 { };
// b1 ( 5, 6, obj1 );
b2 ( 5, 6, obj2 );
// b3 ( 5, 6, obj2 );
c1 ( 5, 6, obj2 );
return 0;
}
Above solution provides a mechanism to enforce what I want; however, the compiler can not give informative error messages to the end user. I would like to have such a nice error mechanism. I would also appreciate, if you pointed out to possible flaws/problems related to the above solution.
Aucun commentaire:
Enregistrer un commentaire