Select a template specialization by enum values for static polimorphism - templates

Here is simplified sample of problem, featuring CRTP:
#include <type_traits>
#include <iostream>
enum ActionTypes {
eInit = 2 << 0,
eUpdate = 2 << 1,
eMultUpdate = 2 << 2
};
template <class Data,
unsigned Actions = eInit|eUpdate|eMultUpdate>
class ActionData
{
template<ActionTypes As /*???*/>
struct action {
static void exec(Data*) { std::cout << "ActionData:: /*dummy*/ exec()\n"; };
static void exec(Data*,int) { std::cout << "ActionData::/*dummy*/ exec(int)\n"; };
};
template<>
struct action < /*???*/ >
{
static void exec(Data*) { /*...*/ };
};
template<>
struct action < /*???*/ >
{
static void exec(Data*, int) { /*...*/ };
};
Data* derived() { return static_cast<Data*>(this); }
protected:
void init() { action<eInit>::exec(derived()); }
void update() { action<eUpdate>::exec(derived()); }
void update(int key) { action<eMultUpdate>::exec(derived()); }
public:
enum Keys { DEFAULT_KEY = -1 };
void call(ActionTypes a, int key = DEFAULT_KEY)
{
switch (a) {
case eInit:
init(); break;
case eUpdate:
if (key == DEFAULT_KEY)
update();
else
case eMultUpdate:
update(key);
}
}
};
class Test : public ActionData<Test, eUpdate>
{
public:
void update() { std::cout << "Test :: update()\n"; }
};
int main()
{
Test actor;
ActionTypes a = eInit;
actor.call(a, 0); // useless here but must be possible.
actor.call(eUpdate, 0);
actor.call(eUpdate);
}
Essentially not all derived classes may implement all handlers, a enum is used to declare that and a dummy version of handler must be called. The problem is that it's not possible to select any implementation but default one using enum and enable_if alone, it requires a non-type parameter, which stupefied me.
PS. Another problem is target platform is limited to C++98\C++03 or tr1 C++11 (no variadic templates). The awkward interface is a legacy of dynamic (but not used as such) polymorphic architecture using function pointers in a big C (not C++!) project. Necessity of pointers or vtable made system unstable to programmer errors leading to vtable being overwritten.

I didn't realize that I should use a partial specialization for all cases including where there is no match:
#include <type_traits>
#include <iostream>
enum ActionTypes {
eInit = 2 << 0,
eUpdate = 2 << 1,
eMultUpdate = 2 << 2
};
template <class Data,
unsigned Actions = eInit|eUpdate|eMultUpdate>
class ActionData
{
// Never gets selected
template<ActionTypes A, typename Enable = void > struct action {};
template< ActionTypes A >
struct action<A, typename std::enable_if<(A & Actions) == 0>::type >
{
static void exec(Data*) { std::cout << "ActionData:: /*dummy*/ exec()\n"; };
static void exec(Data*,int) { std::cout << "ActionData::/*dummy*/ exec(int)\n"; };
};
template< ActionTypes A >
struct action < A, typename std::enable_if<(A & Actions) == eInit>::type >
{
static void exec(Data* o) { o->Data::init(); };
};
template< ActionTypes A >
struct action < A, typename std::enable_if<(A & Actions) == eUpdate>::type >
{
static void exec(Data* o) { o->Data::update(); };
};
template< ActionTypes A >
struct action < A, typename std::enable_if<(A & Actions) == eMultUpdate>::type >
{
static void exec(Data* o, int key) { o->Data::update(key); };
};
Data* derived() { return static_cast<Data*>(this); }
protected:
void init() { action<eInit>::exec(derived()); }
void update() { action<eUpdate>::exec(derived()); }
void update(int key) { action<eMultUpdate>::exec(derived(), key); }
public:
enum Keys { DEFAULT_KEY };
void call(ActionTypes a, int key = DEFAULT_KEY)
{
switch (a) {
case eInit:
init(); break;
case eUpdate:
if (key == DEFAULT_KEY) {
update();
break;
} else {
case eMultUpdate:
update(key);
break;
};
}
}
};
class Test : public ActionData<Test, eUpdate>
{
public:
void update() { std::cout << "Test :: update()\n"; }
};
int main()
{
Test actor;
ActionTypes a = eInit;
actor.call(a, 0);
actor.call(eUpdate);
actor.call(eMultUpdate, 0);
}

Related

C++: How to use different dynamic template in map

my header code:
template <typename T>
class A
{
}
template<> class A<short>;
template<> class A<float>;
in my cpp, i want to use a map to contain different type a, like following code:
class B
{
map<int, A*> a; /* how to declare a */
public:
AddA(int key, int type)
{
if (type == 1)
{
a.insert({ key, new A<short>() });
}
else
{
a.insert({ key, new A<float>() });
}
}
template<typename T>
func(int key, T v)
{
a[key].func(v);
}
};
question: how to implement it?
edit # 0410, here is my solution:
class ABase
{
virtual void func(void* t)=0;
}
template <typename T> A;
template <short> A : public ABase
{
void func(void* t) override
{
auto value = *static_cast<short*>(t);
// do processing
}
template <float> A : public ABase
{
void func(void* t) override
{
auto value = *static_cast<float*>(t);
// do processing
}
CPP: used a map of ABase* for all the template class, and use a virtual func for all template interface
main()
{
map<int, ABase*> objs;
objs.insert({0, new A<short>()});
objs.insert({1, new A<float>()});
auto value=0;
objs[0]->func(&value);
auto value1=0.f;
objs[1]->func(&value1);
}
If you really need to have multiple types in a single map, you can use a map of std::variant. But as already mentioned in the comments, this might be a design problem.
But if you need it, you can proceed with the std::map< int, std::variant<>>. Later on, if you want to access the stored element, you have to call std::visit to pick the element which is stored in std::variant.
See the following example:
template < typename T >
struct A
{
};
// spezialize if needed, here only for demonstration purpose
template <> struct A<short> { void func(short parm) { std::cout << "A<short> with " << parm << std::endl; } };
template <> struct A<float> { void func(float parm) { std::cout << "A<float> with " << parm << std::endl; } };
class B
{
std::map<int, std::variant<A<short>*, A<float>*>> a;
public:
void AddA(int key, int type)
{
if (type == 1)
{
a.insert({ key, new A<short>() });
}
else
{
a.insert({ key, new A<float>() });
}
}
template<typename T>
void func(int key, T v)
{
std::visit( [&v]( auto ptr ) { ptr->func(v); }, a[key] );
}
};
int main()
{
B b;
b.AddA( 1, 1 );
b.AddA( 2, 2 );
b.func( 1, 99 );
b.func( 2, 100 );
}
You can't achieve the problem with templates. Template declaration is only a blueprint for a type candidate.
"A<short>" is the type not "A" itself.
You can achieve your problem through inheritance.
Edit: Code is updated according to #MSalters' comment. Thanks.
#include <iostream>
#include <map>
class A
{
public:
virtual void func(void* x) = 0;
};
class A_Short : public A
{
public:
void func(void* x)
{
short* value = static_cast<short*>(x);
std::cout << "short value: " << *value << std::endl;
}
};
class A_Float : public A
{
public:
void func(void* x)
{
float* value = static_cast<float*>(x);
std::cout << "float value: " << *value << std::endl;
}
};
template<typename T>
class A_Derived : public A
{
public:
void func(void* x)
{
T* value = static_cast<T*>(x);
std::cout << "[Derived] value: " << *value << std::endl;
}
};
class B
{
std::map<int, A*> a; /* how to declare a */
public:
void AddA(int key, int type)
{
if (type == 1)
{
a.insert({ key, new A_Short() });
}
else if(type == 2)
{
a.insert({key, new A_Derived<short>()});
}
else if(type == 3)
{
a.insert({key, new A_Derived<float>()});
}
else
{
a.insert({ key, new A_Float() });
}
}
// Assumes that user knows to use which T for any "key"
template<typename T>
void func(int key, T v)
{
a[key]->func(v);
}
};
int main()
{
B b;
b.AddA(1, 1);
b.AddA(2, 8);
b.AddA(3, 2);
b.AddA(4, 3);
short s = 1;
float f = 7.1;
short s2 = 2;
float f2 = 7.2;
b.func(1, &s);
b.func(2, &f);
b.func(3, &s2);
b.func(4, &f2);
}

class inheriting from multiple template class instances returning their types

I want to inherit multiple times from a base template class and have a method that returns the corresponding value for every type used in the inheritance, look at the test2 instance (following code definitely won't compile, because the getNextData() methods have the same signature and the problem is that I don't know how to fix it), I marked the important lines in the code:
#include <iostream>
namespace ns
{
template<typename Output>
class Base
{
protected:
struct ResultData { bool success; Output data; };
public:
virtual ResultData getNextData() = 0;
};
template<typename Output>
class Derived : public Base<Output> {/*implements some pure virtual method*/};
struct Data
{
int32_t member;
};
struct Final final : public Derived<Data>
{
ResultData getNextData() final
{
return { true, {1} };
}
};
template<typename T1, typename T2 = int32_t>
class DerivedMultiple : public virtual Derived<T1> // <= important
, public Base<T2> // <= important
{
public:
ResultData<T1> getNextData() override { return { false, {} }; }
virtual ResultData<T2> getNextData() { return { false, {} }; }
};
struct FinalMultiple final : public DerivedMultiple<Data, std::string>
{
ResultData getNextData() final { return {true, {1} }; } // <= important
ResultData getNextData() final { return {true, "test"}; } // <= important
};
struct ReferenceT1 {
ReferenceT1(Base<Data>& base) {}; // <= important
};
struct ReferenceT2 {
ReferenceT2(Base<std::string>& base) {}; // <= important
};
}
int main()
{
ns::Final test1;
std::cout << test1.getNextData().success << std::endl;
std::cout << test1.getNextData().data.member << std::endl;
ns::FinalMultiple test2;
std::cout << test2.getNextData().success << std::endl;
std::cout << test2.getNextData()/*for Data*/.data.member << std::endl; // <= important
std::cout << test2.getNextData().success << std::endl;
std::cout << test2.getNextData()/*for std::string*/.data << std::endl; // <= important
ns::ReferenceT1 referenceT1(test2); // <= important
ns::ReferenceT2 referenceT2(test2); // <= important
}
There was an obvious solution to pass the values as reference and fill them in the getNextData(<type>&) method, but that's how it started, I refactored that at the beginning, because I want to return the values, not fill them (many reasons):
bool getNextData(T1& output) override { return false; }
bool getNextData(T2& output) override { return false; }
I tried virtual inheritance, but it didn't help in this context.
I came up with 2 solutions, both bypass the need for different signature in a very dirty way and neither of them works when you uncomment the 2 commented lines in them (can't derive from the base class twice and have those methods returning only the expected type).
First solution:
#include <iostream>
namespace ns
{
template<typename Output>
class Base
{
protected:
struct ResultData { bool success; Output data; };
public:
virtual ResultData getNextData() = 0;
};
template<typename Output>
class Derived : public Base<Output> {};
struct Data
{
int32_t member;
};
struct Final final : public Derived<Data>
{
ResultData getNextData() final
{
return { true, {1} };
}
};
template<typename T1, typename T2 = int32_t>
class DerivedMultiple : public virtual Derived<T1>
//, public Base<T2>
{
protected:
struct ResultDataT2 { bool success; T2 data; };
public:
virtual ResultDataT2 getNextDataT2() { return { false, {} }; }
};
struct FinalMultiple final : public DerivedMultiple<Data, std::string>
{
ResultData getNextData() final
{
return {true, {1} };
}
ResultDataT2 getNextDataT2() final
{
return {true, "test"};
}
};
struct ReferenceT1 {
ReferenceT1(Base<Data>& base) {};
};
struct ReferenceT2 {
ReferenceT2(Base<std::string>& base) {};
};
}
int main()
{
ns::Final test1;
std::cout << test1.getNextData().success << std::endl;
std::cout << test1.getNextData().data.member << std::endl;
ns::FinalMultiple test2;
std::cout << test2.getNextData().success << std::endl;
std::cout << test2.getNextData().data.member << std::endl;
std::cout << test2.getNextDataT2().success << std::endl;
std::cout << test2.getNextDataT2().data << std::endl;
ns::ReferenceT1 referenceT1(test2);
//ns::ReferenceT2 referenceT2(test2);
}
Second solution:
#include <iostream>
namespace ns
{
template<typename Output>
struct ResultData { bool success; Output data; };
template<typename Output>
class Base
{
public:
virtual ResultData<Output> getNextData() = 0;
};
template<typename Output>
class Derived : public Base<Output> {};
struct Data
{
int32_t member;
};
struct Final final : public Derived<Data>
{
ResultData<Data> getNextData() final
{
return { true, {1} };
}
};
template<typename T1, typename T2 = int32_t>
class DerivedMultiple : public virtual Derived<T1>
//, public Base<T2>
{
protected:
struct ResultDataT2 { bool success; T2 data; };
public:
virtual ResultDataT2 getNextDataT2() { return { false, {} }; }
};
struct FinalMultiple final : public DerivedMultiple<Data, std::string>
{
ResultData<Data> getNextData() final
{
return {true, {1} };
}
ResultDataT2 getNextDataT2() final
{
return {true, "test"};
}
};
struct ReferenceT1 {
ReferenceT1(Base<Data>& base) {};
};
struct ReferenceT2 {
ReferenceT2(Base<std::string>& base) {};
};
}
int main()
{
ns::Final test1;
std::cout << test1.getNextData().success << std::endl;
std::cout << test1.getNextData().data.member << std::endl;
ns::FinalMultiple test2;
std::cout << test2.getNextData().success << std::endl;
std::cout << test2.getNextData().data.member << std::endl;
std::cout << test2.getNextDataT2().success << std::endl;
std::cout << test2.getNextDataT2().data << std::endl;
ns::ReferenceT1 referenceT1(test2);
//ns::ReferenceT2 referenceT2(test2);
}
Is there a way in C++ to overcome this problem?
Another thing would be to switch to variadic templates in the solution (so the base class can be inherited more than twice and the multiply derived class can return more than 2 types), but that's optional.
I'm not sure I quite understand what you are trying to achieve, but see if this gives you some ideas.
template <typename Impl, typename Intf, typename Tag>
class ForwardingShim;
template <typename Impl, typename Intf>
class ForwardingShim<Impl, Intf, struct ForwardOne> : public Intf {
public:
typename Intf::ResultData getNextData() final {
return static_cast<Impl*>(this)->getNextDataOne();
}
};
template <typename Impl, typename Intf>
class ForwardingShim<Impl, Intf, struct ForwardTwo> : public Intf {
public:
typename Intf::ResultData getNextData() final {
return static_cast<Impl*>(this)->getNextDataTwo();
}
};
template <typename T1, typename T2>
class MultiDerived :
public ForwardingShim<MultiDerived, Base<T1>, struct ForwardOne>,
public ForwardingShim<MultiDerived, Base<T2>, struct ForwardTwo> {
public:
typename Base<T1>::ResultData getNextDataOne();
typename Base<T2>::ResultData getNextDataTwo();
};
Demo

Store different templated classes in one container without losing information about it's type

I'm currently working on a project where a client part of my application has to be able to create custom templated classes on the server. The server part has to keep track of these created classes and has to remember the types with which the classes has been instantiated. The problem is, that there are around 36 different class-template-combinations that are valid in my application. I'm currently struggling to keep track of these different types in a collection without losing information about my instances.
I'm currently using something like this:
#include <memory>
#include <type_traits>
#include <vector>
enum class data_type : std::uint8_t {
type_int = 1,
type_float,
type_double
};
enum class class_type : std:: uint8_t {
type_A = 1,
type_B
};
struct X {
virtual data_type get_data_type() = 0;
virtual class_type get_class_type() = 0;
};
template <typename T>
struct A : X {
data_type get_data_type() override
{
if (std::is_same<T, int>::value) {
return data_type::type_int;
} else if (std::is_same<T, float>::value) {
return data_type::type_float;
} else if (std::is_same<T, double>::value) {
return data_type::type_double;
} else {
/* ... */
}
}
class_type get_class_type() override
{
return class_type::type_A;
}
};
template <typename T>
struct B : X {
data_type get_data_type() override
{
if (std::is_same<T, int>::value) {
return data_type::type_int;
} else if (std::is_same<T, float>::value) {
return data_type::type_float;
} else if (std::is_same<T, double>::value) {
return data_type::type_double;
} else {
/* ... */
}
}
class_type get_class_type() override
{
return class_type::type_B;
}
};
struct Storage {
template <typename T, template <typename> class Class>
void create() {
Class<T>* t = new Class<T>();
_classes.push_back(std::unique_ptr<X>(t));
}
std::vector<std::unique_ptr<X>> _classes;
};
but I'm wondering if this is the way to go or if there is a more elegant way. Here I would have to always switch through the enums to get the full type out of my Storage class, something like:
switch(_classes.front()->get_class_type()) {
case class_type::type_A:
{
switch(_classes.front()->get_data_type()) {
case data_type::type_int:
{
/* I finally know that it is A<int> */
}
/* ... */
Thanks in advance.
You can consider using std::variant and the std::visit pattern
auto var = std::variant<int, float, double>{};
// assign var to value
std::visit([](auto& value) {
using Type = std::decay_t<decltype(value)>;
if constexpr (std::is_same<Type, int>{}) {
// is an int
} else if (std::is_same<Type, float>{}) {
// is float
} else if (std::is_same<Type, double>{}) {
// is double
}
}, var);
If the if constexpr looks ugly to you then you can substitute it with a handrolled visitor class as well.
class Visitor {
public:
void operator()(int& value) { ... }
void operator()(float& value) { ... }
void operator()(double& value) { ... }
};
auto var = std::variant<int, float, double>{};
// assign var to value
std::visit(Visitor{}, var);
As mentioned in the comments to the question, this is a viable approach that could help:
#include<vector>
#include<memory>
struct Counter {
static int next() {
static int v = 0;
return v++;
}
};
template<typename>
struct Type: Counter {
static int value() {
static const int v = Counter::next();
return v;
}
};
struct X {
virtual int get_data_type() = 0;
virtual int get_class_type() = 0;
};
template <typename T>
struct A : X {
int get_data_type() override {
return Type<T>::value();
}
int get_class_type() override {
return Type<A<T>>::value();
}
};
template <typename T>
struct B : X {
int get_data_type() override {
return Type<T>::value();
}
int get_class_type() override {
return Type<B<T>>::value();
}
};
struct Storage {
template <typename T, template <typename> class Class>
void create() {
Class<T>* t = new Class<T>();
_classes.push_back(std::unique_ptr<X>(t));
}
std::vector<std::unique_ptr<X>> _classes;
};
int main() {
Storage s;
s.create<int, A>();
if(Type<int>::value() == s._classes.front()->get_class_type()) {
//...
};
}
See it running on wandbox.

Defining Visitors Inline in Modern C++ alternate take

I found a very interesting article on
Defining Visitors Inline in Modern C++
The solution proposed is quite complicated though.
I wonder if there is a simpler way of addressing this scenario?
code and example added below to avoid needing to follow link.
Taking the example from the paper, given the following classes:
struct Triangle;
struct Square;
struct PolygonVisitor
{
virtual ~PolygonVisitor() {}
virtual void visit(Triangle& tr) = 0;
virtual void visit(Square& sq) = 0;
};
struct Polygon
{
virtual void accept(PolygonVisitor& v) = 0;
};
struct Triangle : Polygon
{
void accept(PolygonVisitor& v) override
{
v.Visit(*this);
}
};
struct Square : Polygon
{
void accept(PolygonVisitor& v) override
{
v.Visit(*this);
}
};
An inline visitor is constructed and used to work out how many sides a
shape has:
int CountSides(Polygon& p)
{
int sides = 0;
auto v = begin_visitor<PolygonVisitor>()
.on<Triangle>([&sides](Triangle& tr)
{
sides = 3;
})
.on<Square>([&sides](Square& sq)
{
sides = 4;
})
.end_visitor();
p.Accept(v);
return sides;
}
The inline visitor is defined as follows (code taken from
https://github.com/jbcoe/inline_visitor):
template <typename T, typename F, typename BaseInnerVisitor, typename ArgsT>
class ComposeVisitor
{
public:
class InnerVisitor : public BaseInnerVisitor
{
public:
using BaseInnerVisitor::Visit;
typedef typename BaseInnerVisitor::VisitorInterface VisitorInterface;
InnerVisitor(ArgsT&& args)
: BaseInnerVisitor(std::move(args.second)), m_f(std::move(args.first))
{
}
void Visit(T& t) final
{
VisitImpl(t);
}
private:
template <typename F_ = F>
typename std::enable_if<
std::is_assignable<std::function<void(T&)>, F_>::value>::type
VisitImpl(T& t)
{
m_f(t);
}
template <typename F_ = F>
typename std::enable_if<std::is_assignable<
std::function<void(T&, VisitorInterface&)>, F_>::value>::type
VisitImpl(T& t)
{
m_f(t, *this);
}
F m_f;
};
ComposeVisitor(ArgsT&& args) : m_args(std::move(args))
{
}
template <typename Tadd, typename Fadd>
ComposeVisitor<Tadd, Fadd, InnerVisitor, std::pair<Fadd, ArgsT>>
on(Fadd&& f) &&
{
return ComposeVisitor<Tadd, Fadd, InnerVisitor, std::pair<Fadd, ArgsT>>(
std::make_pair(std::move(f), std::move(m_args)));
}
template <typename InnerVisitor_ = InnerVisitor>
typename std::enable_if<!std::is_abstract<InnerVisitor_>::value,
InnerVisitor>::type
end_visitor() &&
{
return InnerVisitor(std::move(m_args));
}
ArgsT m_args;
};
template <typename TVisitorBase>
class EmptyVisitor
{
public:
class InnerVisitor : public TVisitorBase
{
public:
using TVisitorBase::Visit;
typedef TVisitorBase VisitorInterface;
InnerVisitor(std::nullptr_t)
{
}
};
template <typename Tadd, typename Fadd>
ComposeVisitor<Tadd, Fadd, InnerVisitor, std::pair<Fadd, std::nullptr_t>>
on(Fadd&& f) &&
{
return ComposeVisitor<Tadd, Fadd, InnerVisitor,
std::pair<Fadd, std::nullptr_t>>(
std::make_pair(std::move(f), nullptr));
}
};
template <typename TVisitorBase>
EmptyVisitor<TVisitorBase> begin_visitor()
{
return EmptyVisitor<TVisitorBase>();
}
One possible way of tackling this problem is inheriting from the abstract visitor ( PolygonVisitor in the example) a new class (InlineVisitor) that takes in its constructor a std::function for each abstract method it has to implement.
Each abstract method is implemented it in term of the std::function stored
#include <functional>
#include <iostream>
struct Triangle;
struct Square;
struct PolygonVisitor
{
virtual ~PolygonVisitor() {}
virtual void visit(Triangle& tr) = 0;
virtual void visit(Square& sq) = 0;
};
struct Polygon {
virtual void accept(PolygonVisitor& v) = 0;
};
struct Triangle : Polygon
{
void accept(PolygonVisitor& v) override { v.visit(*this); }
};
struct Square : Polygon
{
void accept(PolygonVisitor& v) override { v.visit(*this); }
};
class InlineVisitor : public PolygonVisitor
{
public:
virtual void visit(Triangle& value) { triangleFx_(value); }
virtual void visit(Square& value) { squareFx_(value); }
std::function<void(Triangle&)> triangleFx_;
std::function<void(Square&)> squareFx_;
InlineVisitor(const std::function<void(Triangle&)> triangleFx,
const std::function<void(Square&)> squareFx)
: triangleFx_(triangleFx)
, squareFx_(squareFx) {}
};
int countSides(Polygon& p)
{
int sides = 0;
InlineVisitor countSidesVisitor([&sides](Triangle& tr) { sides = 3; },
[&sides](Square& sq) { sides = 4; });
p.accept(countSidesVisitor);
return sides;
}
int main(int argc, char *argv[])
{
Triangle t;
Square s;
std::cout << "sides of Triangle: " << countSides(t) << std::endl
<< "sides of Square: " << countSides(s) << std::endl;
return 0;
};
The original implementation is more general while this retains the basic idea but is a simpler

C++, generic programming and virtual functions. How do I get what I want?

This is what I would like to do using templates:
struct op1
{
virtual void Method1() = 0;
}
...
struct opN
{
virtual void MethodN() = 0;
}
struct test : op1, op2, op3, op4
{
virtual void Method1(){/*do work1*/};
virtual void Method2(){/*do work2*/};
virtual void Method3(){/*do work3*/};
virtual void Method4(){/*do work4*/};
}
I would like to have a class that simply derives from a template class that provides these method declarations while at the same time making them virtual. This is what I've managed to come up with:
#include <iostream>
template< size_t N >
struct ops : ops< N - 1 >
{
protected:
virtual void DoStuff(){ std::cout<<N<<std::endl; };
public:
template< size_t i >
void Method()
{ if( i < N ) ops<i>::DoStuff(); }
//leaving out compile time asserts for brevity
};
template<>
struct ops<0>
{
};
struct test : ops<6>
{
};
int main( int argc, char ** argv )
{
test obj;
obj.Method<3>(); //prints 3
return 0;
}
However, as you've probably guessed, I am unable to override any of the 6 methods I have inherited. I'm obviously missing something here. What is my error? No, this isn't homework. This is curiosity.
Tested with GCC 4.3. Don't even know why I spent time on this :-/
#include <iostream>
template <std::size_t N>
struct mark
{ };
template <std::size_t N>
struct op : op <N - 1>
{
virtual void do_method (const mark <N>&) = 0;
};
template <>
struct op <1>
{
virtual void do_method (const mark <1>&) = 0;
};
struct test : op <2>
{
template <std::size_t K>
void
method ()
{ do_method (mark <K> ()); }
virtual void do_method (const mark <1>&)
{ std::cout << "1\n"; }
virtual void do_method (const mark <2>&)
{ std::cout << "2\n"; }
};
int
main ()
{
test x;
x.method <1> ();
x.method <2> ();
}
I don't know how to move the "prettifier" method() template function out of test.
template< size_t N >
struct ops : ops< N - 1 >
This codes an endless loop. The recursion doesn't stop when N reaches 0. Add a specialization for the end case, immediately after the primary template:
template<>
struct ops<0> {}
Also, what does this do? Why not just call ops<i>::DoStuff() directly?
template< size_t i >
void Method()
{ if( i < N ) ops<i>::DoStuff(); }
To mimic your original desire:
#define MAKE_OPS(N) template<> struct Ops<N> : Ops<N-1> { virtual void Method##N() = 0; }
template<int N>
struct Ops;
template<>
struct Ops<0> { };
MAKE_OPS(1);
MAKE_OPS(2);
template<> struct Ops<3> : Ops<2> { virtual void Method3() { std::cout << "3" << std::endl; } };
MAKE_OPS(4);
MAKE_OPS(5);
MAKE_OPS(6);
struct Test : Ops<3> {
virtual void Method1() { std::cout << 1 << std::endl; }
virtual void Method2() { std::cout << 2 << std::endl; }
};