рассмотрите следующие микширования, которые предоставляют дополнительную функциональность 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;
}
Я читал, что решения включают в себя следование правилу «SFINAE», однако решения в SO включают ввод кода, специфичного для проверки работоспособности функции-члена (например, Вот). Можно ли минимизировать кодирование, проверяя класс mixin (т.е. TrendSensor
или же EdgeSensor
) включены?
Я ищу решение, которое минимизирует дополнительное кодирование (т.е. создание многострочной структуры, просто чтобы проверить, существует ли один метод) в c ++ 11 (boost может быть очень хорошо использован).
Если это невозможно, как я могу проверить, существует ли функция для конкретного экземпляра и выполнить ее (или нет) соответственно.
В принципе, можно ли что-нибудь поставить перед
EXEC_ONLY_IF_EXISTS ( this->saveTrends(); )
EXEC_ONLY_IF_EXISTS ( this->saveEdges(); )
для того, чтобы условно разрешить код и выполнить его, или вообще удалить его в зависимости от того, является ли mixin частью экземпляра объекта.
благодарю вас!
Вы можете позвонить, в saveSensor()
Парочка нового метода: localTrends()
а также localEdges()
,
Затем вы можете разработать две альтернативные реализации (выбран SFINAE) localTrends()
; первый, этот звонок saveTrends()
, включается только когда TrendSensor
является базовым классом фактического класса, а второй, который не вызывает saveTrends()
иначе (когда TrendSensor
не базовый класс).
Та же стратегия для localEdges()
: две альтернативные реализации (выбран SFINAE), первая, которая вызывает saveEdges()
, включается только когда EdgeSensor<Something>
является базовым классом фактического класса, а второй, который не вызывает saveEdges()
иначе (когда EdgeSensor<Something>
не базовый класс).
Выбор SFINAE для localTrends()
легко, используя std::is_base_of
,
Выбор SFINAE для localEdges()
немного сложнее, потому что вы не можете (или, по крайней мере: я не знаю, как) проверить, если EdgeSensor<Something>
является базовым классом фактического класса, использующего std::is_base_of
потому что я не знаю Something
класс, который является аргументом шаблона EdgeSensor
,
Итак, я разработал шаблон struct
, chkTplInL
(для «checkTemplateInList»), которые получают аргумент «шаблон шаблона» (то есть EdgeSensor
без его Something
шаблон аргумента) и список названий. Эта структура установила constexpr static
логическое значение, которое true
если класс основан на аргументе «шаблон шаблона» (EdgeSensor
, в нашем случае) находится в списке typenames, (что, в нашем случае, это: если EdgeSensor
класс является основой фактического SensorType
учебный класс), 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()
может быть немного проще
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; }
Других решений пока нет …