Я не знаю, использую ли я правильную стратегию, но я хотел бы использовать шаблон с параметрами значения bool, чтобы, когда для method1 и method2 задано значение false, мне не приходилось вызывать fmethod1 или fmethod2. Я мог бы использовать для этого динамические таблицы, но я только что обнаружил, что могу делать это с помощью шаблонов, и я обучал этому синтаксису, как показано ниже:
#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();}
Я могу заявить fmethod1
а также fmethod2
методы в специализациях (установив для возврата true), чтобы он давал следующие результаты:
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
но я хотел бы сделать это так, чтобы мне не нужно было реализовывать method1 или method2 для Caller
если Wrapper
не нужно, но кажется, что компилятор (gcc
) не вижу, что мне никогда не понадобится fmethod1, когда свойство шаблона method1 имеет значение false.
Мой первый вопрос: получу ли я какую-либо выгоду от этого подхода вместо обычного наследования? virtual
подход, который был бы что-то вроде:
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;}
}
…
И во-вторых, любые идеи о том, как я мог бы реализовать эту идею без необходимости реализации Caller fmethod1
?
Вы можете рассмотреть странно повторяющийся шаблон и использовать статический полиморфизм:
#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();
}
В вашем Wrapper
Вы можете переместить звонки на fmethod1
а также fmethod2
в отдельные вспомогательные функции, которые создаются только при наличии правильных аргументов шаблона:
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; }
Поскольку это шаблон класса, функции-члены создаются только в том случае, если они вызываются, и при разрешении перегрузки не будут пытаться вызывать функции, которые не соответствуют аргументам.
Ваши функции отсутствуют const
квалификаторы, но это не относится к вопросу.