Добре, значи си мислех, че ще умра, но най-накрая успях да го направя ç_ç
Първо, използвах обичайните индекси. Тъй като нямам официалните, използвах стари индекси, които написах преди няколко месеца:
template<std::size_t...>
struct indices {};
template<std::size_t N, std::size_t... Ind>
struct make_indices:
make_indices<N-1, N-1, Ind...>
{};
template<std::size_t... Ind>
struct make_indices<0, Ind...>:
indices<Ind...>
{};
След това използвах някои функционални характеристики, намерени някъде в StackOverflow. Те са хубави и мисля, че са еквивалентни на библиотеката Boost, свързана в коментарите:
template<typename T>
struct function_traits:
function_traits<decltype(&T::operator())>
{};
template<typename C, typename Ret, typename... Args>
struct function_traits<Ret(C::*)(Args...) const>
{
enum { arity = sizeof...(Args) };
using result_type = Ret;
template<std::size_t N>
using arg = typename std::tuple_element<N, std::tuple<Args...>>::type;
};
След това успях да напиша правилна функция make_foo
и функция за нейното изпълнение, тъй като и двете трябва да използват индекси. Внимавайте, това е просто грозно:
template<typename Function, std::size_t... Ind>
auto make_foo_(Function&& func, indices<Ind...>)
-> Foo<
typename function_traits<typename std::remove_reference<Function>::type>::result_type,
typename function_traits<typename std::remove_reference<Function>::type>::template arg<Ind>...>
{
using Ret = typename function_traits<typename std::remove_reference<Function>::type>::result_type;
return { std::function<Ret(typename function_traits<typename std::remove_reference<Function>::type>::template arg<Ind>...)>(func) };
}
template<typename Function, typename Indices=make_indices<function_traits<typename std::remove_reference<Function>::type>::arity>>
auto make_foo(Function&& func)
-> decltype(make_foo_(std::forward<Function>(func), Indices()))
{
return make_foo_(std::forward<Function>(func), Indices());
}
Кодът е някак грозен и нечетлив, но определено работи. Надяваме се, че сега не разчита на някакво поведение, дефинирано от внедряването. Освен това благодаря на всички за съветите, помогнаха! :)
int main()
{
auto lambda = [](int i, float b, long c)
{
return long(i*10+b+c);
};
auto foo = make_foo(lambda);
std::cout << foo(5, 5.0, 2) << std::endl; // 57, it works!
}
А ето и пример на живо :)
person
Morwenn
schedule
12.11.2013
T
(илиF
, ако предпочитате). - person chris   schedule 12.11.2013std::function
като аргумент, е достатъчно, за да разреши ламбда. Всъщност трябва да го използвате като единственото претоварване, защото приема както ламбда, така и функционални указатели. - person 0x499602D2   schedule 12.11.2013std::tuple<Args...>
в тялото на класа. Така че трябва да имамArgs...
като параметър на шаблон на клас. - person Morwenn   schedule 12.11.2013std::tuple<Args...>
е частен иmake_foo
няма достъп до него. - person Morwenn   schedule 13.11.2013Foo
всъщност беше функтор, мемоизиращ дадена чиста функция. Затова използвамstd::unordered_map<std::tuple<Args...>, Ret>
за кеширане на двойките аргументи/резултат. - person Morwenn   schedule 13.11.2013