Reputation: 2557
I don't know if I am using the right strategy, but I would like to use template with bool value parameters, so that when either method1 and method2 are set to false I don't have to call fmethod1 or fmethod2. I could use dynamic tables for doing that, but I just discovered that I could do this with templates, and I was training this syntax usage as below:
#include<iostream>
template<bool method1, bool method2>
class Caller {
public:
Caller(const float prop1, const float prop2):prop1(prop1),prop2(prop2){;}
float prop1;
float prop2;
bool fmethod1(){
return prop1;
}
bool fmethod2(){
return prop2;
}
void mainMethod(){
std::cout << "Caller<" << method1 << "," << method2 << ">(" << prop1 << ")" << std::endl;
std::cout << "fmethod1()" << fmethod1() << std::endl;
std::cout << "fmethod2()" << fmethod2() << std::endl;
};
};
template<>
class Caller<true,false> {
public:
Caller(const float prop2):prop2(prop2){;}
float prop2;
// I can declare here to return true, but this
// shouldn't be called in Wrapper, since Wrapper method1 is set
// to false (the first "or" on wrapper should be set to true and
// compiler shouldn't need this method.)
bool fmethod1();
bool fmethod2(){
return prop2;
}
void mainMethod(){
std::cout << "Caller<true,false>" << std::endl;
std::cout << "fmethod2()" << fmethod2() << std::endl;
};
};
template<>
class Caller<false,true> {
public:
Caller(const float prop1):prop1(prop1){;}
float prop1;
bool fmethod1(){
return prop1;
}
bool fmethod2(); // Same here
void mainMethod(){
std::cout << "Caller<false,true>" << std::endl;
std::cout << "fmethod1()" << fmethod1() << std::endl;
};
};
template<>
class Caller<false,false> {
public:
bool fmethod1(){
return true;
}
bool fmethod2(){
return true;
}
void mainMethod(){
std::cout << "Caller<false,false>" << std::endl;
std::cout << "fmethod1()" << fmethod1() << std::endl;
std::cout << "fmethod2()" << fmethod2() << std::endl;
};
};
template<template<bool, bool> class holded_t,bool method1, bool method2>
class Wrapper{
public:
holded_t<method1,method2> holded;
Wrapper():holded(holded_t<method1,method2>()){;}
Wrapper(float prop1):holded(holded_t<method1,method2>(prop1)){;}
Wrapper(float prop1, float prop2):holded(holded_t<method1,method2>(prop1,prop2)){;}
void mainMethod(){
if( !method1 || holded.fmethod1() ){
if( !method2 || holded.fmethod2() ){
holded.mainMethod();
} else {
std::cout << "holded method2 is false" << std::endl;
}
} else {
std::cout << "holded method1 is false" << std::endl;
}
}
};
int main(){
Wrapper<Caller,false,false> holder_ex_false_false;
holder_ex_false_false.mainMethod();
Wrapper<Caller,false,true> holder_ex_false_true(0);
holder_ex_false_true.mainMethod();
Wrapper<Caller,true,false> holder_ex_true_false(0);
holder_ex_true_false.mainMethod();
Wrapper<Caller,true,true> holder_ex_true_true(0,0);
holder_ex_true_true.mainMethod();
Wrapper<Caller,true,true> holder_ex_true_true1(1,0);
holder_ex_true_true1.mainMethod();
Wrapper<Caller,true,true> holder_ex_true_true2(0,1);
holder_ex_true_true2.mainMethod();
Wrapper<Caller,true,true> holder_ex_true_true3(1,1);
holder_ex_true_true3.mainMethod();
}
I can declare fmethod1
and fmethod2
methods in the specializations (setting it to return true) so that it give the following results:
Caller<false,false>
fmethod1()1
fmethod2()1
Caller<false,true>
fmethod1()0
fmethod2()1
Caller<true,false>
fmethod1()1
fmethod2()0
holded method1 is false
holded method2 is false
holded method1 is false
Caller<1,1>(1)
fmethod1()1
fmethod2()1
but I wanted a way to do this so that I don't need to implement method1 or method2 for the Caller
if the Wrapper
doesn't need it, but it seems that the compiler (gcc
) can't see that I will never need fmethod1 when template property method1 is false.
My first question is if I get any benefit in this approach instead on the normal inherit virtual
approach, which would be something like:
class Caller{
public:
virtual bool fmethod1(){return true;}
virtual bool fmethod2(){return true;}
}
class CallerMethod1Active: public Caller{
public:
float prop1;
bool fmethod1(){return prop1;}
bool fmethod2(){return true;}
}
…
And second, any ideas on how could I implement this idea without needing to implement Caller fmethod1
?
Upvotes: 0
Views: 113
Reputation: 14714
In your Wrapper
you can move the calls to fmethod1
and fmethod2
into separate helper functions which are only instantiated if the correct template arguments are present:
void mainMethod(){
if( testmethod1(std::integral_constant<bool, method1>()) ){
if( testmethod2(std::integral_constant<bool, method2>()) ){
holded.mainMethod();
} else {
std::cout << "holded method2 is false" << std::endl;
}
} else {
std::cout << "holded method1 is false" << std::endl;
}
}
bool testmethod1(std::true_type) { return holded.fmethod1(); }
bool testmethod1(std::false_type) { return false; }
bool testmethod2(std::true_type) { return holded.fmethod2(); }
bool testmethod2(std::false_type) { return false; }
Because this is a class template, the member functions are only instantiated if they are called, and overload resolution will not try to call the functions which don't match the arguments.
Your functions are missing const
qualifiers but that doesn't pertain to the question.
Upvotes: 1
Reputation:
You might consider the curiously recurring template pattern and use static polymorphism:
#include <iostream>
template<typename Derived>
class BasicCaller
{
protected:
BasicCaller() {}
public:
void method() {
static_cast<Derived*>(this)->method1();
static_cast<Derived*>(this)->method2();
}
protected:
bool method1() { return false; }
bool method2() { return false; }
};
class CallNone : public BasicCaller<CallNone> {};
class CallFirst : public BasicCaller<CallFirst>
{
friend class BasicCaller<CallFirst>;
protected:
bool method1() {
std::cout << "First\n";
return true;
}
};
class CallSecond : public BasicCaller<CallSecond>
{
friend class BasicCaller<CallSecond>;
protected:
bool method2() {
std::cout << "Second\n";
return true;
}
};
class CallBoth : public BasicCaller<CallBoth>
{
friend class BasicCaller<CallBoth>;
protected:
bool method1() {
std::cout << "Both First\n";
return true;
}
bool method2() {
std::cout << "Both Second\n";
return true;
}
};
int main()
{
std::cout << "CallNone\n";
CallNone a;
a.method();
std::cout << "CallFirst\n";
CallFirst b;
b.method();
std::cout << "CallSecond\n";
CallSecond c;
c.method();
std::cout << "CallBoth\n";
CallBoth d;
d.method();
}
Upvotes: 1