c ++ 11: вызов функции variadi c с элементами вектора и автоматический вывод числа аргументов - PullRequest
1 голос
/ 07 февраля 2020

Попытка расширить пример, найденный здесь: { ссылка }

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

Не удается скомпилировать вызов call_helper: ошибка: ошибка разбора в аргументе шаблона

Кажется, я не могу понять как передать constexpr, который возвращает количество аргументов в качестве аргумента шаблона.

Это то, что у меня есть до сих пор:

#include <vector>

template <typename R, typename ... T>
constexpr std::size_t get_args_count( R(*f)(T ...))
{
   return sizeof...(T);
}

template< std::size_t... Ns >
struct indices {
    typedef indices< Ns..., sizeof...( Ns ) > next;
};

template< std::size_t N >
struct make_indices {
    typedef typename make_indices< N - 1 >::type::next type;
};

template<>
struct make_indices< 0 > {
    typedef indices<> type;
};

void abc(int) {}
void abc2(int, int) {}

// helper function because we need a way
// to deduce indices pack

template<typename Func, size_t... Is>
void call_helper2(Func f, const std::vector<int>& args, indices<Is...>)
{
    f( args[Is]... ); // expand the indices pack
}

template<typename Func, size_t N>
void call_helper(Func f, const std::vector<int>& args)
{
    call_helper2(f, args, typename make_indices<N>::type());
}

template<typename Func>
void call(Func f, const std::vector<int>& args)
{
    if (args.size() < get_args_count(f)) throw 42;
    call_helper<get_args_count(decltype(f))>(f, args); // error: parse error in template argument list
}

int main()
{
    struct F
    {
        void operator()(int, int, int, int) {}
    };

    std::vector<int> v(4);
    call(&abc2, v);
    call(&abc, v);
    call([&](int, int, int) { (void)v.empty(); }, v);
    call(F(), v);
}

Что я пропускаю или делаю неправильно? Любая помощь приветствуется.

РЕДАКТИРОВАТЬ: добавлены случаи использования функтора и лямбда

Ответы [ 2 ]

1 голос
/ 08 февраля 2020
Ответ

YS C решает проблему для обычных функций, но он не работает с лямбдами и функторами. Чтобы это работало и с функторами и лямбдами, мне пришлось добавить перегрузку call (в зависимости от решения в { ссылка }):

template< std::size_t... Ns >
struct indices {
    typedef indices< Ns..., sizeof...( Ns ) > next;
};

template< std::size_t N >
struct make_indices {
    typedef typename make_indices< N - 1 >::type::next type;
};

template<>
struct make_indices< 0 > {
    typedef indices<> type;
};

void abc(int) {}
void abc2(int, int) {}

// helper function because we need a way
// to deduce indices pack

template<typename Func, size_t... Is>
void call_helper2(Func f, const std::vector<int>& args, indices<Is...>)
{
    f( args[Is]... ); // expand the indices pack
}

template<typename Func, size_t N>
void call_helper(Func f, const std::vector<int>& args)
{
    call_helper2(f, args, typename make_indices<N>::type());
}

template<class R, class ... T>
void call(R(*f)(T ...), const std::vector<int>& args)
{
    // this overload is used for regular functions
    if (args.size() < sizeof...(T)) throw 42;
    call_helper<decltype(f), sizeof...(T)>(f, args);
}

template <typename T>
struct func_traits:
    public func_traits<decltype(&T::operator())>
{};

template <typename C, typename R, typename... Args>
struct func_traits<R(C::*)(Args...) const>
{
    enum { arity = sizeof...(Args) };
};

template<typename Func>
void call(Func f, const std::vector<int>& args)
{
    // this overload is used for functors and lambdas
    using traits = func_traits<decltype(f)>;
    if (args.size() < traits::arity) throw 42;
    call_helper<decltype(f), traits::arity>(f, args);
}

int main()
{
    struct F
    {
        void operator()(int, int, int, int) const {}
    };

    std::vector<int> v(4);
    call(&abc2, v);
    call(&abc, v);
    call([&](int, int, int) { (void)v.empty(); }, v);
    call(F(), v);
}
1 голос
/ 07 февраля 2020

Было две ошибки:

  1. В call_helper<get_args_count(decltype(f))>(f, args), get_args_count(decltype(f)) не имеет смысла, так как get_args_count принимает указатель на функцию, а не на тип (очевидно);
  2. A Аргумент функции никогда не может быть constexpr (я позволю вам искать SO, почему).

Как исправить?

Вам нужно извлечь количество аргументов f как как можно скорее, прежде чем оно станет чем-то иным, чем выражением, используемым в контексте constexpr.

#include <vector>

template< std::size_t... Ns >
struct indices {
    typedef indices< Ns..., sizeof...( Ns ) > next;
};

template< std::size_t N >
struct make_indices {
    typedef typename make_indices< N - 1 >::type::next type;
};

template<>
struct make_indices< 0 > {
    typedef indices<> type;
};

void abc(int) {}
void abc2(int, int) {}

// helper function because we need a way
// to deduce indices pack

template<typename Func, size_t... Is>
void call_helper2(Func f, const std::vector<int>& args, indices<Is...>)
{
    f( args[Is]... ); // expand the indices pack
}

template<typename Func, size_t N>
void call_helper(Func f, const std::vector<int>& args)
{
    call_helper2(f, args, typename make_indices<N>::type());
}

template<class R, class ... T>
void call(R(*f)(T ...), const std::vector<int>& args)
{
    if (args.size() < sizeof...(T)) throw 42;
    call_helper<
        decltype(f), sizeof...(T)
    >(f, args);
}

int main()
{
    std::vector<int> v(2);
    call(&abc2, v);
}
...