#c #templates #metaprogramming
#c #шаблоны #метапрограммирование
Вопрос:
У меня есть много классов, предоставляющих внутренний тип с именем Binding
. Например, один из них может быть:
struct Message
{
struct Binding
{
};
};
Я вызываю функцию apply
, подобную этой:
apply< Message >([](Message::Bindingamp; x)
{
// setup binding fields
});
ибо я написал
template <class TMessage, class TBindingExpression>
void apply(const TBindingExpressionamp; expr)
{
typedef typename TMessage::Binding BindingType;
BindingType binding;
expr(binding);
apply(MessageUtil::typeId< TMessage >(), binding);
}
Поскольку Message
это немного избыточно в том, как я вызываю apply
, я хотел бы заставить компилятор выводить Message
, чтобы я мог писать
apply([](Message::Binding x)
{
//...
});
Пока я застрял здесь:
template <class TBindingExpression>
void apply(const TBindingExpressionamp; expr)
{
// I get the type of the argument which is Message::Binding in this example
typedef typename std::tuple_element
<
0,
FunctionTraits< TBindingExpression >::ArgumentTypes
>
::type BindingType;
// so I can invoke my expression
BindingType binding;
expr(binding);
// But now I need the type of the outer class, i.e. Message
typedef typename MessageTypeFromBinding< BindingType >::Type MessageType;
apply(MessageUtil::typeId< MessageType >(), binding);
}
Есть ли способ написать / достичь MessageTypeFromBinding
?
Очевидно, что это чистое любопытство и косметические проблемы.
Комментарии:
1. IIRC это невозможно (аналогично получению пространства имен, в котором был объявлен тип). Однако вы можете указать typedef
Binding
. Кроме того, объекты функций обычно передаются по значению; опасно полагаться на признаки функции для получения единственного типа параметра первого параметраoperator()
или аналогичного, рассмотрим перегруженныеoperator()
или даже полиморфные лямбды C 1y.2. @dyp: почему использование my
FunctionTraits
для получения типа одного аргумента опасно?3. Каким образом аргумент шаблона второго типа является избыточным? Как компилятор должен знать, каким
BindingType
должен быть тип, и, следовательно, какую перегрузку вызывать при вызовеTBindingExpression
?4. @mister почему, потому что это работает только для небольшого подмножества вызываемых объектов.
5. В c 14 вызов
apply< Message >([](autoamp; x) { // setup binding fields });
, который устраняет избыточность.
Ответ №1:
template<class T>struct inner_class_of{using outer_class=T;};
struct Message {
struct Binding:inner_class_of<Message> {
};
};
template<class T>
inner_class_of<T> get_outer_helper(inner_class_of<T>constamp;);
template<class T>
using outer_class_of_t = typename decltype(get_outer_helper(std::declval<T>()))::outer_class;
теперь outer_class_of_t<Message::Binding>
есть Message
.
Я сделал его немного промышленным, так как он работает, даже если Binding
скрывается outer_class
.
Вы можете удалить помощник и переписать outer_class_of_t=typename T::outer_class
, если хотите.