Я хочу отправлять функции на основе определенного пользователем «тега» моих типов ввода. Например, я определил тег SomeSpecificObjectType
и в классе Object
помечаю этот класс как SomeSpecificObjectType
.
struct SomeSpecificObjectType{};
template<typename T>
class Object
{
public:
Object(T&&in): m_data(in){};
typedef SomeSpecificObjectType ObjectTag;
T m_data;
};
Теперь у меня есть еще один объект, у которого нет этого тега. Так что я его не трогаю.
template<typename T>
class OtherObject
{
public:
OtherObject(T&&in): m_data(in){};
T m_data;
};
Теперь я определяю структуру для проверки тега, который я определил выше.
template<typename T, typename Enable=void>
struct is_some_specific_object_type
{
static constexpr bool value = false;
};
template<typename T>
struct is_some_specific_object_type<T, typename std::enable_if<std::is_same<typename T::ObjectTag, SomeSpecificObjectType>::value>::type>
{
static constexpr bool value = true;
};
Мои функции:
template<typename T, typename std::enable_if<!is_some_specific_object_type<T>::value>::type* = nullptr>
void some_func(const T & data)
{
std::cout <<"something" <<std::endl;
}
template<typename T, typename std::enable_if<is_some_specific_object_type<T>::value>::type* = nullptr>
void some_func(const T & data)
{
std::cout <<"something else" << std::endl;
}
Кажется, это работает.
Однако представьте, что у меня есть класс, определение которого скрыто от меня (HiddenObject
) — это означает, что я не могу просто добавить «тег» SomeSpecificObjectType
к этому классу. По сути я хочу is_some_specific_object_type::value == true
для этого HiddenObject
. Есть ли способ сделать это без редактирования класса HiddenObject
template<typename T>
class HiddenObject
{
public:
HiddenObject(T&&in): m_data(in){};
T m_data;
};
Конечный желаемый результат:
int main()
{
Object obj(123);
OtherObject o_obj(123);
some_func(obj);
some_func(o_obj);
//HiddenObject h_obj(123);
//some_func(h_obj); ---> print "something else"
return 0;
}
Редактировать: Кому-то не понравилось, что я использовал слово «черта», я заменю это слово на «Тег», оно кажется более подходящим, чтобы избежать путаницы.
Пробовали ли вы поместить эту «черту» в отдельный класс шаблона, чтобы можно было просто специализировать ее для разных классов? Это похоже на магию шаблонов черного пояса, но вы даже можете попробовать заставить реализацию по умолчанию искать «черту» в самом классе, чтобы вы могли просто поместить ее туда, как в первом примере для вашего собственного класса, и вам нужно только беспокойтесь о специализации для классов за пределами вашей сферы.
«Есть ли способ сделать это без редактирования класса HiddenObject»: Если вы следуете подходу с тегами вместо того, чтобы проверять фактические свойства нужного вам типа, как это обычно делают «черты» в C++, то вы, конечно, можете просто специализироваться is_some_specific_object_type
для этого конкретного типа. Но эту специализацию необходимо поместить либо в заголовок HiddenObject
, либо в заголовок, определяющий is_some_specific_object_type
, перед любым первым использованием признака для этого конкретного типа, возможно, с упреждающим объявлением для достижения этой цели, иначе вы рискуете случайно вызвать нарушения ODR.
@Прохожий - я посмотрю
@user17732522 user17732522 Да, это именно то, что мне нужно, не знаю, почему это пришло мне в голову. Спасибо
Просто добавьте специализацию is_some_specific_object_type
для HiddenObject
:
template <typename T> struct is_HiddenObject : std::false_type {};
template <typename T> struct is_HiddenObject<HiddenObject<T>> : std::true_type {};
template<typename T>
struct is_some_specific_object_type<T, std::enable_if_t<is_HiddenObject<T>::value>> : std::true_type{};
Обратите внимание, что вам, возможно, придется добавить/переставить специализации, если ваш тип (HiddenObject
) соответствует нескольким специализациям.
По какой-то причине это решение пришло мне в голову. Я мог бы просто сделать это! Спасибо за вашу помощь!
Это не то, что означают черты в C++. См. например
std::iterator_traits
, а также ответ на ваш вопрос.