You can call, in saveSensor()
, a couple of new method: localTrends()
and localEdges()
.
Then, you can develop two alternative implementations (SFINAE selected) of localTrends()
; the first one, that call saveTrends()
, enabled only when the TrendSensor
is a base class of the actual class, and the second one, that doesn't call saveTrends()
, otherwise (when TrendSensor
isn't a base class).
Same strategy for localEdges()
: two alternative implementations (SFINAE selected), the first one, that call saveEdges()
, enabled only when the EdgeSensor<Something>
is a base class of the actual class, and the second one, that doesn't call saveEdges()
, otherwise (when EdgeSensor<Something>
isn't a base class).
The SFINAE selection for localTrends()
is easy, using std::is_base_of
.
The SFINAE selection for localEdges()
is a little more complicated because you can't (or at least: I don't know how to) check if EdgeSensor<Something>
is a base class of the actual class using std::is_base_of
because I don't know the Something
class that is the template argument of EdgeSensor
.
So I've developed a template struct
, chkTplInL
(for "checkTemplateInList") that receive a "template template" argument (that is EdgeSensor
without its Something
template argument) and a list of typenames. This struct set a constexpr static
boolean value that is true
if a class based on the "template template" argument (EdgeSensor
, in our case) is in the list of typenames, (that, in our case, is: if a EdgeSensor
class is base of the actual SensorType
class), false
otherwise.
The following is a working example
#include <type_traits>
#include <iostream>
class PeakSensor { };
class TroughSensor { };
class TroughEdge { };
template<typename EdgeType>
class EdgeSensor : public EdgeType
{ public: void saveEdges(){} };
class TrendSensor
{ public: void saveTrends(){} };
template <template <typename ...> class, typename ...>
struct chkTplInL;
template <template <typename ...> class C>
struct chkTplInL<C>
{ static constexpr bool value = false; };
template <template <typename ...> class C, typename T0, typename ... Ts>
struct chkTplInL<C, T0, Ts...>
{ static constexpr bool value = chkTplInL<C, Ts...>::value; };
template <template <typename ...> class C, typename ... Ts1, typename ... Ts2>
struct chkTplInL<C, C<Ts1...>, Ts2...>
{ static constexpr bool value = true; };
template<typename ... SensorType>
class BaseSensor : public SensorType ...
{
public:
template <template <typename...> class C = EdgeSensor>
typename std::enable_if<
true == chkTplInL<C, SensorType...>::value>::type localEdges ()
{ this->saveEdges(); std::cout << "localEdges case A" << std::endl; }
template <template <typename...> class C = EdgeSensor>
typename std::enable_if<
false == chkTplInL<C, SensorType...>::value>::type localEdges ()
{ std::cout << "localEdges case B" << std::endl; }
template <typename B = TrendSensor>
typename std::enable_if<
true == std::is_base_of<B, BaseSensor>::value>::type localTrends ()
{ this->saveTrends(); std::cout << "localTrends case A" << std::endl; }
template <typename B = TrendSensor>
typename std::enable_if<
false == std::is_base_of<B, BaseSensor>::value>::type localTrends ()
{ std::cout << "localTrends case B" << std::endl; }
void saveSensor ()
{
this->localTrends();
this->localEdges();
}
};
int main ()
{
BaseSensor<EdgeSensor<TroughEdge> , TrendSensor> eps1;
eps1.saveSensor(); // print localTrends case A
// and localEdges case A
BaseSensor<TrendSensor> eps2;
eps2.saveSensor(); // print localTrends case A
// and localEdges case B
BaseSensor<EdgeSensor<TroughSensor>> eps3;
eps3.saveSensor(); // print localTrends case B
// and localEdges case A
BaseSensor<> eps4;
eps4.saveSensor(); // print localTrends case B
// and localEdges case B
return 0;
}
If you can use a C++14 compiler, you can use std::enable_if_t
, so the SFINAE selection for localEdges()
and localTrends()
can be a little simpler
template <template <typename...> class C = EdgeSensor>
std::enable_if_t<
true == chkTplInL<C, SensorType...>::value> localEdges ()
{ this->saveEdges(); std::cout << "localEdges case A" << std::endl; }
template <template <typename...> class C = EdgeSensor>
std::enable_if_t<
false == chkTplInL<C, SensorType...>::value> localEdges ()
{ std::cout << "localEdges case B" << std::endl; }
template <typename B = TrendSensor>
std::enable_if_t<
true == std::is_base_of<B, BaseSensor>::value> localTrends ()
{ this->saveTrends(); std::cout << "localTrends case A" << std::endl; }
template <typename B = TrendSensor>
std::enable_if_t<
false == std::is_base_of<B, BaseSensor>::value> localTrends ()
{ std::cout << "localTrends case B" << std::endl; }