2014-09-25 2 views
1

Я искал SO и другие форумы, которые ищут способ определения параметров и типа возврата лямбда, а затем действуют на эти параметры, чтобы выполнить поиск типов при репо объектов, которые уже были созданы. Дело в том, чтобы создать способ делать инъекцию зависимостей на каком-либо произвольно определенном лямбда-выражении. Например, если у меня есть что-то вроде следующего:compile time loop over templated type

auto lambda = [] (MyObject o) -> string { return o.name(); }; 

Я мог бы определить типы параметров лямбда, и поиска соответствующего объекта типа MyObject, а затем вызвать lambda передавая этот объект «автомагически».

До сих пор я нашел способы определения типов списков параметров лямбды и возвращаемые типы, используя следующие шаблоны:

template <typename T> 
struct function_traits 
    : public function_traits<decltype(&T::operator())> 
{}; 
// For generic types, directly use the result of the signature of its 'operator()' 

template <typename ClassType, typename ReturnType, typename... Args> 
struct function_traits<ReturnType(ClassType::*)(Args...) const> 
    // we specialize for pointers to member function 
{ 
    enum { arity = sizeof...(Args) }; 
    // arity is the number of arguments. 

    typedef ReturnType result_type; 

    template <size_t i> 
    struct arg 
    { 
     typedef typename std::tuple_element<i, std::tuple<Args...>>::type type; 
     // the i-th argument is equivalent to the i-th tuple element of a tuple 
     // composed of those arguments. 
    }; 
}; 

который я нашел в this SO пост (очень аккуратно).

Теперь, что я хотел бы сделать, это реализовать какое-то время компиляции эквивалент следующее:

// first get the type of the lambda using the above 'function_traits' template 
typedef function_traits<decltype(lambda)> traits; 
// now iterate over the traits and get the type of each argument, then print out the type name 
for (size_t i = 0u; i < size_t(traits::arity); ++i) 
{ 
    // The point to focus on here is `traits::args<i>::type` 
    std::cout << typeid(traits::args<i>::type).name() << std::end; 
} 

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

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

+1

Цикл в целом вы можете omplish с помощью шаблона class Loop {...} ', который делегирует' Loop 'для следующей итерации и шаблон специализации класс Loop {...}' для прекращения но мне пришлось бы немного погрузиться в проблему, чтобы выяснить, как применить ее к этому делу. – cdhowie

+0

Существует два типичных подхода к этой проблеме: рекурсия и расширение пакета с использованием трюков индексов. К сожалению, вы не говорите нам, какие проблемы у вас были с рекурсией или с тем, что вы пробовали с рекурсией. Для трюков индексов см., Например, http://stackoverflow.com/a/7858971 – dyp

+0

Вы даже можете найти несколько вопросов под названием «Итерации над кортежем» или аналогичные в SO, например. http://stackoverflow.com/q/1198260 – dyp

ответ

1

С C++ 14, вы можете сделать:

namespace detail 
{ 
    template <typename T, std::size_t ... Is> 
    void display(std::index_sequence<Is...>) 
    { 
     std::initializer_list<int>{((std::cout << typeid(typename T::template arg<Is>::type).name() << std::endl), 0)...}; 
    } 

} 

template <typename T> 
void display() 
{ 
    detail::display<T>(std::make_index_sequence<T::arity>()); 
} 

И использовать его:

using traits = function_traits<decltype(lambda)>; 

display<traits>(); 

Live example

Если застрял с C++ 11, есть много места для поиска реализации make_index_sequence и index_sequence

+0

+1 Спасибо за ваш ответ, но это не совсем трюк. Это ближе к тому, что я хочу, чем к тому, что делаю, но я ищу способ получить типы каждого параметра в лямбда, чтобы я мог выполнять поиск типов. Я мог бы немного ввести вас в заблуждение с моим примером использования. Я собираюсь больше копать в 'index_sequence'! – pje