可变参数模板:如何检查特定 class 是否是包的一部分,并在 class 存在的情况下从该 class 执行特定方法

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

考虑以下为 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();
}

哪里

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

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

我读到解决方案涉及遵循 "SFINAE" 规则,但是,SO 中的解决方案涉及键入特定于检查成员函数是否有效的代码(例如 here)。是否可以通过检查是否包含 mixin class(即 TrendSensorEdgeSensor)来最小化编码?

我正在寻找一种在 c++11 中最大限度地减少额外编码(即创建多行结构只是为了检查是否存在单个方法)的解决方案(很可能会使用提升)。

如果这不可能,我如何检查特定实例的函数是否存在并相应地执行(或不执行)。

基本上什么都可以放在

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

以便有条件地允许代码并执行它,或者完全删除它,具体取决于 mixin 是否是实例化对象的一部分。 谢谢!

您可以在 saveSensor() 中调用一些新方法:localTrends()localEdges()

然后,您可以开发localTrends()的两个替代实现(选择SFINAE);第一个调用 saveTrends(),仅当 TrendSensor 是实际 class 的基础 class 时启用,第二个不调用 saveTrends(),否则(当 TrendSensor 不是基数 class 时)。

localEdges() 的相同策略:两个替代实现(选择 SFINAE),第一个调用 saveEdges(),仅当 EdgeSensor<Something> 是基数 class 的实际 class,第二个不调用 saveEdges(),否则(当 EdgeSensor<Something> 不是基础 class 时)。

localTrends() 的 SFINAE 选择很简单,使用 std::is_base_of

localEdges() 的 SFINAE 选择有点复杂,因为您不能(或者至少:我不知道如何)检查 EdgeSensor<Something> 是否为基数 class 的实际 class 使用 std::is_base_of 因为我不知道 Something class 是 EdgeSensor.

的模板参数

所以我开发了一个模板 structchkTplInL(用于 "checkTemplateInList"),它接收一个 "template template" 参数(即 EdgeSensor 没有它的Something 模板参数)和类型名称列表。如果基于 "template template" 参数(EdgeSensor,在我们的例子中)的 class 在列表中,则此结构设置一个 constexpr static 布尔值 true typenames,(在我们的例子中,是:如果 EdgeSensor class 是实际 SensorType class 的基础),否则 false

下面是一个工作示例

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

如果能用C++14的编译器,就可以用std::enable_if_t,所以localEdges()localTrends()的SFINAE选择可以稍微简单一些

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