可变参数模板:如何检查特定 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(即 TrendSensor
或 EdgeSensor
)来最小化编码?
我正在寻找一种在 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
.
的模板参数
所以我开发了一个模板 struct
、chkTplInL
(用于 "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; }
考虑以下为 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(即 TrendSensor
或 EdgeSensor
)来最小化编码?
我正在寻找一种在 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
.
所以我开发了一个模板 struct
、chkTplInL
(用于 "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; }