Re: std::function<...> получение количества и типа параметров
От: Warturtle  
Дата: 20.04.14 08:16
Оценка: +2
Здравствуйте, c-smile, Вы писали:

CS>Есть такой полезный тип как std::function<signature>.

CS>Стоит задача получения количества аргументов в сигнатуре функции и их типов. В compile time есс-но.
CS>Почему-то в std::function я этого не нашел.

CS>...

Кстати, в бусте есть:

#include <stdio.h>
#include <boost/function_types/function_arity.hpp>

using namespace boost::function_types;

template< class CallableT >
size_t GetArity(CallableT fnc)
{
    return function_arity< CallableT >::value;
}

int main(int argc, char * argv[])
{
    printf("main:%u", GetArity(main));
}
Re: std::function<...> получение количества и типа параметров
От: Alexander G Украина  
Дата: 19.04.14 07:01
Оценка: 38 (1)
Здравствуйте, c-smile, Вы писали:

CS>Что-то можно с этим сделать?



Старые добрые специализации?


#include <iostream>
#include <functional>

using namespace std;

typedef int value;


// Общий шаблон
template<class Signature>
function<void(int, value[])>
thunk( function<Signature> f );


// Специализация для одного аргумента
template<class R, class Arg1>
function<void(int, value[])>
thunk( function<R(Arg1)> f )
{
    return [f](int, value v[]) -> R
    {
        return f(v[0]);
    };
}

// Специализация для двух аргументов
template<class R, class Arg1, class Arg2>
function<void(int, value[])>
thunk( function<R(Arg1, Arg2)> f )
{
    return [f](int, value v[]) -> R
    {
        return f(v[0], v[1]);
    };
}

// и так далее...


void f1(int p1) { cout << "f1\t" << p1 << "\n"; }
void f2(int p1, int p2) { cout << "f2\t" << p1 << "\t" << p2 << "\n"; }

int main() {
    int a1[] = {1};
    int a2[] = {3, 4};
    thunk( std::function<void(int)>(f1) )(1, a1);
    thunk( std::function<void(int, int)>(f2) )(2, a2);
    return 0;
}


http://ideone.com/rOEOOc
Русский военный корабль идёт ко дну!
Re[3]: std::function<...> получение количества и типа параметров
От: Alexander G Украина  
Дата: 20.04.14 10:52
Оценка: 38 (1)
Здравствуйте, c-smile, Вы писали:

CS>Но вот c лямбдами, без явного приведения, это не работает.


Лябмды в первом посте не заказывали


#include <iostream>
#include <functional>

using namespace std;

typedef int value;

// для одного аргумента


// Констатнтый метод - и лямбда и std::function идут сюда
template<class F, class R, class Arg1>
function<void(int, value[])>
thunk_impl( F f, R(F::*)(Arg1) const  )
{
    return [f](int, value v[]) -> R
    {
        return f(v[0]);
    };
}

// Неконстантный метод
template<class F, class R, class Arg1>
function<void(int, value[])>
thunk_impl( F f, R(F::*)(Arg1) )
{
    return [f](int, value v[]) -> R
    {
        return f(v[0]);
    };
}

// Свободная функция
template<class F, class R, class Arg1>
function<void(int, value[])>
thunk_impl( F f, R(Arg1) )
{
    return [f](int, value v[]) -> R
    {
        return f(v[0]);
    };
}

// для двух аргументов

// Констатнтый метод - и лямбда и std::function идут сюда
template<class F, class R, class Arg1, class Arg2>
function<void(int, value[])>
thunk_impl( F f, R(F::*)(Arg1, Arg2) const )
{
    return [f](int, value v[]) -> R
    {
        return f(v[0], v[1]);
    };
}

// Неконстантный метод
template<class F, class R, class Arg1, class Arg2>
function<void(int, value[])>
thunk_impl( F f, R(F::*)(Arg1, Arg2) )
{
    return [f](int, value v[]) -> R
    {
        return f(v[0], v[1]);
    };
}

// Свободная функция
template<class F, class R, class Arg1, class Arg2>
function<void(int, value[])>
thunk_impl( F f, R(Arg1, Arg2) )
{
    return [f](int, value v[]) -> R
    {
        return f(v[0], v[1]);
    };
}


// и так далее...

// Методы
template<class F>
function<void(int, value[])>
thunk( F f )
{
    return thunk_impl<F>(f, &F::operator());
}


// Указатели на функции
template<class F>
function<void(int, value[])>
thunk( F* f )
{
    return thunk_impl<F*>(f, f);
}

void f1(int p1) { cout << "f1\t" << p1 << "\n"; }
void f2(int p1, int p2) { cout << "f2\t" << p1 << "\t" << p2 << "\n"; }
 
int main() {
int a1[] = {1};
int a2[] = {3, 4};
 
// case 1
auto ufunc = thunk( f1 );
ufunc(2,a1);
 
 
// case 2
auto ff2 = [](int p1, int p2) { cout << "ff2\t" << p1 << "\t" << p2 << "\n"; };
 
auto ufunc2 = thunk( ff2 );
ufunc2(2,a2);
 
return 0;
}


http://ideone.com/mKk6tj
Русский военный корабль идёт ко дну!
Re: std::function<...> получение количества и типа параметров
От: jazzer Россия Skype: enerjazzer
Дата: 21.04.14 04:30
Оценка: 19 (1)
Здравствуйте, c-smile, Вы писали:

CS>Стоит задача получения количества аргументов в сигнатуре функции и их типов. В compile time есс-но.


это часть бустовских type_traits (т.е. в какой-то момент должна появиться и в std)
http://www.boost.org/doc/libs/1_55_0/libs/type_traits/doc/html/boost_typetraits/reference/function_traits.html
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[3]: std::function<...> получение количества и типа параметров
От: jazzer Россия Skype: enerjazzer
Дата: 21.04.14 07:12
Оценка: 6 (1)
Здравствуйте, PM, Вы писали:

PM>Здравствуйте, jazzer, Вы писали:


CS>>>Стоит задача получения количества аргументов в сигнатуре функции и их типов. В compile time есс-но.


J>>это часть бустовских type_traits (т.е. в какой-то момент должна появиться и в std)

J>>http://www.boost.org/doc/libs/1_55_0/libs/type_traits/doc/html/boost_typetraits/reference/function_traits.html

PM>Интересно, почему типы аргументов фнукции сделали через typedef see-below argN_type; вместо хранения всех типов аргументов в tuple или mpl::vector. Как в таком случае использовать n-ый аргумент в runtime? Допустим, у меня есть


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

В бусте есть библиотека, лежащая между type_traits и MPL — function_types:
http://www.boost.org/doc/libs/1_55_0/libs/function_types/doc/html/boost_functiontypes/introduction.html
parameter_types<...>::type возвращает то, что тебе надо (то, что можно использовать с MPL).

PM>
PM>// здесь куча специализаций, сгенерированных Boost.Preprocessor:
PM>//   call_helper<F, MAX_N>::exec(..),
PM>//   call_helper<F, MAX_N - 1>::exec(..),
PM>//   call_helper<F, 0>::exec(..)
PM>// в которых делается конверсия args[i] к типу аргумента function и вызов function:
PM>//   return function(boost::get<arg_type<0>>(args[0]), boost::get<arg_type<1>>(args[1]), ... boost::get<arg_type<N-1>>(args[N-1]));
PM>

Ну, если ты уже используешь Boost.Preprocessor, то нет проблем в нем же сгенерить и вызовы argN_type — заодно и компилиться будет быстрее
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
std::function<...> получение количества и типа параметров
От: c-smile Канада http://terrainformatica.com
Дата: 19.04.14 05:13
Оценка:
Есть такой полезный тип как std::function<signature>.
Стоит задача получения количества аргументов в сигнатуре функции и их типов. В compile time есс-но.
Почему-то в std::function я этого не нашел.

Что бы получить что-то типа этого:

template<TF>
  std::function<void(int, value[])>
    thunk( TF f ) {
      switch(TF::argc) {
        case 0: return [f](int argc, value argv[]) { f(); }; 
        case 1: return [f](int argc, value argv[]) { f(argv[0].coerce<TF::argt<0>>() ); };
        case 2: return [f](int argc, value argv[]) { f(argv[0].coerce<TF::argt<0>>(), argv[0].coerce<TF::argt<1>>() ); };
        ...
      }
     return [f](int argc, value argv[]) { assert(WTF); }
   }


Т.е. из функции с произвольной сигнатурой получаем унифицированную функцию типа
void foo(int argc, value argv[])


Я что-то проглядел в std::function?

Есть вот такой вариант, но потому что
гладиоус VS2010/12 он не подходит ибо variadic templates.

Что-то можно с этим сделать?
Re[2]: std::function<...> получение количества и типа параметров
От: c-smile Канада http://terrainformatica.com
Дата: 19.04.14 16:29
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Старые добрые специализации?


Да, это было первое что я попробовал.

Но вот c лямбдами, без явного приведения, это не работает.

        // case 2
    auto ff2 = [](int p1, int p2) { cout << "ff2\t" << p1 << "\t" << p2 << "\n"; };
    
    auto ufunc2 = thunk( ff2 ); // не шмогла она здесь разобраться
    ufunc2(2,a2);


http://ideone.com/SOrGRk
Re[3]: std::function<...> получение количества и типа параметров
От: uzhas Ниоткуда  
Дата: 19.04.14 18:19
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Но вот c лямбдами, без явного приведения, это не работает.


лямбды в первом посте не упоминались Ж)
пару ссылок кину, могут пригодиться
http://www.youtube.com/watch?v=_zgq6_zFNGY
http://stackoverflow.com/questions/7943525/is-it-possible-to-figure-out-the-parameter-type-and-return-type-of-a-lambda
Re[4]: std::function<...> получение количества и типа параметров
От: uzhas Ниоткуда  
Дата: 19.04.14 18:22
Оценка:
Здравствуйте, uzhas, Вы писали:

U>пару ссылок кину, могут пригодиться

+ http://stackoverflow.com/questions/6202021/detecting-function-object-functor-and-lambda-traits
Re[2]: std::function<...> получение количества и типа параметров
От: PM  
Дата: 21.04.14 06:04
Оценка:
Здравствуйте, jazzer, Вы писали:

CS>>Стоит задача получения количества аргументов в сигнатуре функции и их типов. В compile time есс-но.


J>это часть бустовских type_traits (т.е. в какой-то момент должна появиться и в std)

J>http://www.boost.org/doc/libs/1_55_0/libs/type_traits/doc/html/boost_typetraits/reference/function_traits.html

Интересно, почему типы аргументов фнукции сделали через typedef see-below argN_type; вместо хранения всех типов аргументов в tuple или mpl::vector. Как в таком случае использовать n-ый аргумент в runtime? Допустим, у меня есть

typedef boost::variant<bool, int, std::string> argument;
typedef std::vector<argument> arguments;

template <typename F, size_t N>
struct call_helper
{
    typedef boost::function_traits<F> F_traits;

    F_traits::result_type exec(F function, arguments const& args);
};

// здесь куча специализаций, сгенерированных Boost.Preprocessor:
//   call_helper<F, MAX_N>::exec(..),
//   call_helper<F, MAX_N - 1>::exec(..),
//   call_helper<F, 0>::exec(..)
// в которых делается конверсия args[i] к типу аргумента function и вызов function:
//   return function(boost::get<arg_type<0>>(args[0]), boost::get<arg_type<1>>(args[1]), ... boost::get<arg_type<N-1>>(args[N-1]));
 
template<typename F>
void call(F function, arguments const& args)
{
    typedef boost::function_traits<F> F_traits;
    if (args.size() != F_traits::arity)
    {
        throw std::runtime_error("argument count does not match function definition");
    }
    return call_helper<function, F_traits::arity>::exec(args);
}


Сейчас используется велосипед с boost::mpl::vector для arg_type и тип аргумента n я получаю c помощью boost::mpl::at_c<arg_type, n>

Про boost::function_traits я как-то не знал но даже зная теперь, не могу понять как его применять в данном случае.

Прдеполагаю, что в С+11 с variadic templates использование std::tuple для arg_type всё будет еще проще.
Re[4]: std::function<...> получение количества и типа параметров
От: PM  
Дата: 21.04.14 09:02
Оценка:
Здравствуйте, jazzer, Вы писали:


J>>>это часть бустовских type_traits (т.е. в какой-то момент должна появиться и в std)

J>>>http://www.boost.org/doc/libs/1_55_0/libs/type_traits/doc/html/boost_typetraits/reference/function_traits.html

PM>>Интересно, почему типы аргументов фнукции сделали через typedef see-below argN_type; вместо хранения всех типов аргументов в tuple или mpl::vector. Как в таком случае использовать n-ый аргумент в runtime? Допустим, у меня есть


J>Ну, если ты уже используешь Boost.Preprocessor, то нет проблем в нем же сгенерить и вызовы argN_type — заодно и компилиться будет быстрее


Спасибо, про Boost.FunctionTypes тоже не знал

Да, действительно, я могу нагенерировать препроцессором нужных argN_type. Но в перспективе включения function_traits в С++1z все равно не очень понятно, что делать с argN_type. Однако, если использовать std::tuple для типов аргументов функции, то получить n-й тип с использованием std::tuple_element в С++11 проще простого.

Хотя, уже сейчас счастливчики в С++11 могут использовать простой function_traits на variadic templates (который кстати, работает и с std::function, что изначльно требовалось c-smile): http://functionalcpp.wordpress.com/2013/08/05/function-traits/
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.