Шаблон шаблона условной компиляции

Я не знаю, использую ли я правильную стратегию, но я хотел бы использовать шаблон с параметрами значения 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?

0

Решение

Вы можете рассмотреть странно повторяющийся шаблон и использовать статический полиморфизм:

#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();
}
1

Другие решения

В вашем 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 квалификаторы, но это не относится к вопросу.

1

По вопросам рекламы [email protected]