2015-10-13 3 views
8

Легко написать шаблон, который будет детектировать наличие конкретного элемента в пределах типа с помощью void_t:Определение присутствия произвольного члена

#include <type_traits> 

// This comes from cppreference 
template<typename... Ts> struct make_void { typedef void type;}; 
template<typename... Ts> using void_t = typename make_void<Ts...>::type; 

// primary template handles types that have no ::aMember 
template< class T, class = void_t<> > 
struct has_aMember : std::false_type { }; 

// specialization recognizes types that do have a ::aMember 
template< class T > 
struct has_aMember<T, void_t<decltype(T::aMember)>> : std::true_type { }; 

Теперь, если я хочу, чтобы обнаружить, является ли какой-либо другой член нет, я должен был бы скопировать и вставить шаблоны детектора и просто изменить aMember к otherMember:

template< class T, class = void_t<> > 
struct has_otherMember : std::false_type { }; 

template< class T > 
struct has_otherMember<T, void_t<decltype(T::otherMember)>> : std::true_type { }; 

Я хотел бы избежать этого копирования-вставки и передать имя элемента в качестве параметра для более общего варианта шаблон обнаружения:

template< class T, class member, class = void_t<> > 
struct has_arbitrary_member : std::false_type { }; 

template< class T, class member > 
struct has_arbitrary_member<T, void_t<decltype(T::member)>> : std::true_type { }; 

так, что я мог бы использовать этот has_arbitrary_member, передавая тип и имя элемента в качестве параметра шаблона:

std::cout << has_arbitrary_member<MyType, aMember>(); 
std::cout << has_arbitrary_member<MyType, otherMember>(); 

Однако, с определением набросал я выше, это не будет компилировать , Есть ли другой способ реализовать такую ​​функциональность?

+0

Лучшее, что вы можете сделать, это что-то вроде ['std :: experimental :: is_detected'] (http://en.cppreference.com/w/cpp/experimental/is_detected). –

+2

Что значит «нравится»? Блок кода * выше * * аналогичен * этим двум строкам. Каковы ваши жесткие требования и как блок кода выше их не соответствует вашим требованиям? Я мог бы написать лучшую версию вашего кода выше (скажем, с 'is_detected'), но я не имел бы способа, если это то, что вы хотите. – Yakk

+0

@Yakk Я добавил предложение в конец вопроса, чтобы уточнить мое намерение более четко. Конечно, void_t не является требованием, хотя я вижу, что 'is_detected' реализуется с использованием' void_t'. Помогает ли это? – Rostislav

ответ

7

То, что вы пытаетесь сделать, вообще невозможно, потому что вы не можете подавить поиск по имени по адресу aMember, если вы не измените поток токенов с помощью макроса. Из этого следует, что вам никогда не удастся использовать имя, которое не входит в сферу действия, если только вы не находитесь в настоящий момент внутри SFINAE, который подавляет ошибку.

Это означает, что вам действительно нужно написать отдельный шаблон для каждого имени.

Это один из тех случаев, когда использование макросов - не плохая идея, хотя это зависит от того, действительно ли вам нужно проверять членов определенного имени или есть ли лучшие способы достижения вашей цели.

+0

Это скорее теоретический вопрос, вызванный любопытством. Спасибо за ответ! – Rostislav

+0

@ Rostislav За что его стоит не слишком сложно сделать с натяжением – soandos

3

Нет, вы не можете передавать имя участника в качестве параметра шаблона без упоминания того, из какого класса/структуры следует имя члена.

И если этот класс/структура не имеет этого имени участника, тогда код имеет ошибку.

Теперь void_t< decltype(&MyType::some_member) > либо void, либо сбой замены в зависимости от того, существует ли some_member. Часто это решает проблему SFINAE, где вам не нужно время компиляции bool.

Если вы хотите запускать код, если какой-то тип не есть член, может сделать это с помощью тщательного выбора порядка перегрузки или специализации шаблона и т.д.

Это не такой мощный, как has_arbitrary_member<MyType, some_member>.

template<class T> 
using some_member_type = decltype(std::declval<T>().some_member); 

простой признак, что с std::experimental::is_detected вы можете сделать:

is_detected_v< some_member_type, T > 

или

template<class T> 
constexpr bool has_some_member_v = is_detected_v< some_member_type, T >; 

, который ведет себя как has_arbitrary_member<MyType, some_member>. Я считаю, что это лучше всего на практике.

+0

Спасибо! Я просто надеялся, что что-то пропустил, и в этом случае есть способ скопировать-вставить или макросы. Но, по крайней мере, я узнал что-то новое - материал is_detected. Небольшой вопрос - правильно ли, что Основы библиотеки v2 - это TS, нацеленный на C++ 17? – Rostislav

Смежные вопросы