Как я могу вывести внешний тип внутреннего типа в C ?

#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 , если хотите.