#c #templates #parameters #c 11 #variadic-templates
#c #шаблоны #параметры #c 11 #переменные-шаблоны
Вопрос:
Простите любое незнание вывода типа C в этом, но я хотел бы иметь возможность переносить определение пакета параметров, чтобы позже я мог протестировать внутренний тип. Возможно ли это? Что-то вроде:
template <typename... Args> struct Entity {
struct Inner {
typedef Args... entity_args_t;
};
struct SomeOtherInner {
typedef Args... entity_args_t;
};
};
struct ThingA : Entity<int, string> {
};
struct ThingB : Entity<string, string> {
};
//Want to accept variations of Entity<...>::Inner,
//not Entity<...>::SomeOtherInner
template<typename I>
struct is_Entity_Inner {
static const bool value
= is_same<
typename Entity<typename I::entity_args_t...>::Inner
, I
>::value
;
};
Oui? Нет?
Ответ №1:
Определить:
template<typename ...> struct types;
Затем:
template <typename... Args> struct Entity {
struct Inner {
typedef types<Args...> entity_args_t;
};
struct SomeOtherInner {
typedef types<Args...> entity_args_t;
};
};
Затем вы можете перейти entity_args_t
к шаблону, который имеет частичную специализацию для types<T...>
. Если вы введете def Entity
, вы можете вместо этого написать частичную специализацию для Entity<T...>
, что может иметь больше смысла в вашем случае
template <typename... Args> struct Entity {
struct Inner {
// Equivalent: typedef Entity entity_args_t;
typedef Entity<Args...> entity_args_t;
};
struct SomeOtherInner {
typedef Entity<Args...> entity_args_t;
};
};
Итак, имея typedef для entity_args_t
equal Entity<Args...>
, вы могли бы написать это следующим образом (непроверенный, но должен работать):
template<typename ProbablyInner, typename ProbablyEntity>
struct is_inner_impl : std::false_type
{ };
template<typename ProbablyInner, typename ...Args>
struct is_inner_impl<ProbablyInner, Entity<Args...>>
: std::is_same<
typename Entity<Args...>::Inner
ProbablyInner>
{ };
template<typename ProbablyInner, typename = std::true_type>
struct is_inner : std::false_type
{ };
template<typename ProbablyInner>
struct is_inner<ProbablyInner,
std::integral_constant<bool, is_inner_impl<
ProbablyInner,
typename ProbablyInner::entity_args_t>::value>>
: std::true_type
{ };
Комментарии:
1. Итак, в
is_Entity_Inner
метафункции я бы вместо этого имелis_same<typename I::entity_args_t::template Inner, I>::value
?2. @pheedbaq критическая точка — это то, к чему вы обращаетесь
::entity_args_t
. Если вы хотите получитьis_inner
yieldfalse
для произвольных других типов, вам нужно получить доступ к типу в контексте SFINAE, чтобы, если не вызывается элемент::entity_args_t
, не возникло ошибки во время компиляции.3. @litb Не совсем уверен, что понял ваш последний комментарий. Это то, что
typename = void
выполняется в качестве второго параметраis_inner
? Если::entity_args_t
элемент существует, то компилятор сопоставляет его со специализацией. Если нет, то, даже если элемент не существует, он сопоставляет его сtypename = void
версией?4. @pheedbaq впоследствии я изменил свой код, чтобы не использовать
enable_if
. Я думаю, что это раздувает код. Если::entity_args_t
существует, то он может учитывать специализацию и соответствует ли она аргументам (аргументы являются<whatever is passed, void>
).enable_if
то, что используется, всегда даст результатvoid
в случае успеха (если элемент существует). В случае неуспеха (то есть когдаis_inner_impl<>::value
вычисляетсяfalse
) не существует::type
элемента, и поэтому возникает ошибка SFINAE. Примерно то же самое происходит с моейintegral_constant<>
версией сейчас.5. ОК. Кажется, я понял. Очень признателен!