nass nass - 2 months ago 8
C++ Question

variadic templates: how can I check if a specific class is part of the pack, and execute a specific method from that class if the class exists

consider the following mixings that provide additional functionality to the

BaseSensor
class.

class PeakSensor{ /*...*/ };
class TroughSensor{ /*...*/ };

template<typename EdgeType> //EdgeType can be PeakSensor or TroughtSensor
class EdgeSensor : public EdgeType
{
public:
void saveEdges(){}
}

class TrendSensor
{
public:
void saveTrends(){}
}

template<typename ... SensorType>
class BaseSensor : public SensorType ... //SensorType can be TrendSensor, EdgeSensor or others...
{
public:
void saveSensor();
}


where

template<typename ... SensorType>
void BaseSensor<SensorType...>::saveSensor()
{
this->saveTrends();
this->saveEdges();
}


and main.cpp

int main(int , const char **)
{
{ //this works
BaseSensor<EdgeSensor<TroughEdge> , TrendSensor> eps;
eps.saveSensor();
cout << endl;
}

{ //this cannot not find "saveSensorEdges()", so it won't compile
BaseSensor<TrendSensor> eps;
eps.saveSensor();
cout << endl;
}
return 0;
}


I have read that solutions involve following "SFINAE" rule however, the solutions in SO involve typing code specific to checking if a member function works (for example here). Is it possible to minimize coding by checking if the mixin class (ie
TrendSensor
or
EdgeSensor
) are included?

I am searching for a solution that minimizes additional coding (ie creating a multiple line struct just to check if a single method exists) in c++11 (boost may very well be used).

If this is not possible how could I check if the function exists for a specific instance and execute it (or not) accordingly.

Basically, can anything be placed in front of

EXEC_ONLY_IF_EXISTS ( this->saveTrends(); )
EXEC_ONLY_IF_EXISTS ( this->saveEdges(); )


in order to conditionally allow the code and execute it , or remove it altogether depending on whether the mixin is part of the instantiated object.
thank you!

Answer

I'm not sure it's a good idea but... if you know a class that can enable your saveSensor(), you can check (std::is_base_of) if is base of your current class and enable two different members.

Like this

#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 <typename ...>
struct checkEdgeSensor;

template <>
struct checkEdgeSensor<>
 { static constexpr bool value = false; };

template <typename T0, typename ... Ts>
struct checkEdgeSensor<T0, Ts...>
 { static constexpr bool value = checkEdgeSensor<Ts...>::value; };

template <typename T, typename ... Ts>
struct checkEdgeSensor<EdgeSensor<T>, Ts...>
 { static constexpr bool value = true; };

template<typename ... SensorType>
class BaseSensor : public SensorType ...
{
   public:
      template <typename B = void>
      typename std::enable_if<true == checkEdgeSensor<B, SensorType...>::value,
               void>::type localEdges ()
       { this->saveEdges(); std::cout << "localEdges case A" << std::endl; }

      template <typename B = void>
      typename std::enable_if<false == checkEdgeSensor<B, SensorType...>::value,
               void>::type localEdges ()
       { std::cout << "localEdges case B" << std::endl; }

      template <typename B = TrendSensor>
      typename std::enable_if<true == std::is_base_of<B,
               BaseSensor<SensorType...>>::value, void>::type localTrend ()
       { this->saveTrends(); std::cout << "localTrend case A" << std::endl; }

      template <typename B = TrendSensor>
      typename std::enable_if<false == std::is_base_of<B,
               BaseSensor<SensorType...>>::value, void>::type localTrend ()
       { std::cout << "localTrend case B" << std::endl; }

      void saveSensor ()
       {
         this->localTrend();
         this->localEdges();
       }
};


int main () 
 {
   BaseSensor<EdgeSensor<TroughEdge> , TrendSensor> eps1;
   eps1.saveSensor();  // print localTrend case A
                       // and   localEdges case A

   BaseSensor<TrendSensor> eps2;
   eps2.saveSensor(); // print localTrend case A
                      // and   localEdges case B

   BaseSensor<EdgeSensor<TroughSensor>> eps3;
   eps3.saveSensor(); // print localTrend case B
                      // and   localEdges case A

   BaseSensor<> eps4;
   eps4.saveSensor(); // print localTrend case B
                      // and   localEdges case B

   return 0;
 }
Comments