可变参数模板:如何检查特定类是否是包的一部分,如果类存在,则从该类执行特定方法

时间:2016-09-18 20:25:26

标签: c++ c++11 methods variadic-templates exists

考虑以下混合,为BaseSensor类提供附加功能。

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

我已经读到解决方案涉及以下&#34; SFINAE&#34;但是,SO中的解决方案涉及键入特定于检查成员函数是否有效的代码(例如here)。是否可以通过检查mixin类(即TrendSensorEdgeSensor)是否包含在内来最小化编码?

我正在寻找一种最小化额外编码的解决方案(即创建一个多行结构,以检查是否存在单个方法)在c ++ 11中(可以很好地使用boost)。

如果无法做到这一点,我怎么能检查特定实例是否存在该函数并相应地执行它。

基本上,任何事情都可以放在

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

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

1 个答案:

答案 0 :(得分:2)

您可以在saveSensor()中使用以下几种新方法致电:localTrends()localEdges()

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

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

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

localEdges()的SFINAE选择稍微复杂一点,因为你不能(或者至少:我不知道如何)检查EdgeSensor<Something>是否是基类使用std::is_base_of的实际课程,因为我不知道Something类是EdgeSensor的模板参数。

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

以下是一个工作示例

false

如果您可以使用C ++ 14编译器,则可以使用#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; } ,因此std::enable_if_tlocalEdges()的SFINAE选择可能会更简单

localTrends()