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; }