std::function, could not deduce template argument
От: c-smile Канада http://terrainformatica.com
Дата: 12.02.15 20:16
Оценка: 3 (1)
Есть вот такая конструкция

#include <functional>
#include <iostream>

template <typename T>
void f(std::function<void(T)> g)
{
    std::cout << "1 arg:";
    g(1);
}

template <typename T1, typename T2>
void f(std::function<void(T1 t1,T2 t2)> g)
{
    std::cout << "2 args:";
    g(1,2);
}

int main(int argc, char* argv[])
{
    auto func1 = [](int x) { std::cout << x << std::endl; };
    auto func2 = [](int x, int y) { std::cout << x << y << std::endl; };

    f(func1);
    f(func2);

    return 0;
}


Попытка скомпилировать дает

error C2784: 'void f(std::function<void(T)>)' : could not deduce template argument for 'std::function<void(T)>' from 'main::<lambda_015bd0dc27990c8871eddd8030a68e56>' d:\tests\functional.cpp

Как бы исхитриться?

Ну или получить количество параметров std::function wrapper и их типы. Знаю как это сделать с пом. variadic templates, но на руках VS 2010, там этого нет.
Re: std::function, could not deduce template argument
От: _NN_ www.nemerleweb.com
Дата: 12.02.15 20:47
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Как бы исхитриться?

CS>Ну или получить количество параметров std::function wrapper и их типы. Знаю как это сделать с пом. variadic templates, но на руках VS 2010, там этого нет.

Ну если есть решение на вариадках, то несложно нагенерировать специализации.

Вроде как decltype поддерживается в VS 2010.

Вот вариант решения https://github.com/kennytm/utils/blob/master/traits.hpp. Переписать несложно будет для 2010 если других проблем не появится .
Идея проста, специализируем по operator() .

function_traits<decltype(lambda)>::arity содержит количество аргументов.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: std::function, could not deduce template argument
От: c-smile Канада http://terrainformatica.com
Дата: 12.02.15 21:43
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Здравствуйте, c-smile, Вы писали:


CS>>Как бы исхитриться?

CS>>Ну или получить количество параметров std::function wrapper и их типы. Знаю как это сделать с пом. variadic templates, но на руках VS 2010, там этого нет.

_NN>Ну если есть решение на вариадках, то несложно нагенерировать специализации.


_NN>Вроде как decltype поддерживается в VS 2010.


А как decltype тут поможет?
Re: std::function, could not deduce template argument
От: andyp  
Дата: 12.02.15 22:45
Оценка: 44 (1)
Если можешь прожить без auto, то так

int main(int argc, char* argv[]) { 
    std::function<void(int)> func1 = [](int x) { std::cout << x << std::endl; }; 
    std::function<void(int,int)> func2 = [](int x, int y) { std::cout << x << y << std::endl; }; 
    f(func1); 
    f(func2); 
    return 0; 
}
Re[2]: std::function, could not deduce template argument
От: c-smile Канада http://terrainformatica.com
Дата: 12.02.15 23:41
Оценка:
Здравствуйте, andyp, Вы писали:

A>Если можешь прожить без auto, то так


A>
A>int main(int argc, char* argv[]) { 
A>    std::function<void(int)> func1 = [](int x) { std::cout << x << std::endl; }; 
A>    std::function<void(int,int)> func2 = [](int x, int y) { std::cout << x << y << std::endl; }; 
A>    f(func1); 
A>    f(func2); 
A>    return 0; 
A>}
A>


В принципе это вариант, да.
Re: std::function, could not deduce template argument
От: jazzer Россия Skype: enerjazzer
Дата: 13.02.15 01:22
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Ну или получить количество параметров std::function wrapper и их типы. Знаю как это сделать с пом. variadic templates, но на руках VS 2010, там этого нет.


Под решением с вариадиками ты имеешь в виду вот это?
http://stackoverflow.com/a/7943765
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[2]: std::function, could not deduce template argument
От: c-smile Канада http://terrainformatica.com
Дата: 13.02.15 02:27
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Здравствуйте, c-smile, Вы писали:


CS>>Ну или получить количество параметров std::function wrapper и их типы. Знаю как это сделать с пом. variadic templates, но на руках VS 2010, там этого нет.


J>Под решением с вариадиками ты имеешь в виду вот это?

J>http://stackoverflow.com/a/7943765

Да, именно это.
Re[3]: std::function, could not deduce template argument
От: _NN_ www.nemerleweb.com
Дата: 13.02.15 06:22
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Да, именно это.


А в чем проблема сгенерировать необходимое количество специализаций вручную ?

//template <typename ClassType, typename ReturnType, typename... Args>
//struct function_traits<ReturnType(ClassType::*)(Args...) const>

template <typename ClassType, typename ReturnType, typename Arg1>
struct function_traits<ReturnType(ClassType::*)(Arg1) const> { static const unsigned arity = 1;... }

template <typename ClassType, typename ReturnType, typename Arg1, typename Arg2>
struct function_traits<ReturnType(ClassType::*)(Arg1, Arg2) const> { static const unsigned arity = 2; ... }

...
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[4]: std::function, could not deduce template argument
От: c-smile Канада http://terrainformatica.com
Дата: 13.02.15 19:39
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>А в чем проблема сгенерировать необходимое количество специализаций вручную ?


Слышишь эхо комбинаторного взрыва? Нет? А он есть...

От 0 до 8-ми аргументов. Да по всем типам функций: member/free, const/non-const, throws/not-throws, volatile и не очень...
Re[5]: std::function, could not deduce template argument
От: _NN_ www.nemerleweb.com
Дата: 13.02.15 20:12
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Слышишь эхо комбинаторного взрыва? Нет? А он есть...

CS>От 0 до 8-ми аргументов. Да по всем типам функций: member/free, const/non-const, throws/not-throws, volatile и не очень...

И что с того ? Простой скрипт все нагенерирует.
Коль нет вариадиков, хоть так извратиться.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[5]: std::function, could not deduce template argument
От: PM  
Дата: 13.02.15 20:23
Оценка:
Здравствуйте, c-smile, Вы писали:

_NN>>А в чем проблема сгенерировать необходимое количество специализаций вручную ?


CS>Слышишь эхо комбинаторного взрыва? Нет? А он есть...

CS>От 0 до 8-ми аргументов. Да по всем типам функций: member/free, const/non-const, throws/not-throws, volatile и не очень...

Можно нагенерировать код с помощью Boost.Preprocessor: https://github.com/pmed/v8pp/blob/7f758ffd0c1ae1c2032c7643899fc4ea098c47cf/v8pp/proto.hpp
Или отдельным внешним скриптом.

Хотя, если доступен Boost, в нем кажется есть похожее: http://www.boost.org/doc/libs/1_57_0/libs/function_types/doc/html/index.html
Re[6]: std::function, could not deduce template argument
От: c-smile Канада http://terrainformatica.com
Дата: 13.02.15 22:05
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Здравствуйте, c-smile, Вы писали:


CS>>Слышишь эхо комбинаторного взрыва? Нет? А он есть...

CS>>От 0 до 8-ми аргументов. Да по всем типам функций: member/free, const/non-const, throws/not-throws, volatile и не очень...

_NN>И что с того ? Простой скрипт все нагенерирует.

_NN>Коль нет вариадиков, хоть так извратиться.

2**7 = 128 деклараций ... да ну нафиг.

Лучше уж люди руками напишут

function<int(int,int)> sum = [](int a, int b) { return a + b; };


вместо модного

auto sum = [](int a, int b) { return a + b; };
Re[6]: std::function, could not deduce template argument
От: c-smile Канада http://terrainformatica.com
Дата: 13.02.15 22:18
Оценка:
Здравствуйте, PM, Вы писали:

PM>Хотя, если доступен Boost, в нем кажется есть похожее: http://www.boost.org/doc/libs/1_57_0/libs/function_types/doc/html/index.html


Это для одного из headers моего SDK, требовать еще наличия boost совсем не comme il faut ни разу.
Re[7]: std::function, could not deduce template argument
От: PM  
Дата: 14.02.15 06:58
Оценка:
Здравствуйте, c-smile, Вы писали:

PM>>Хотя, если доступен Boost, в нем кажется есть похожее: http://www.boost.org/doc/libs/1_57_0/libs/function_types/doc/html/index.html

CS>Это для одного из headers моего SDK, требовать еще наличия boost совсем не comme il faut ни разу.

Я бы отказался от поддержки старых компиляторов и требовал С++11

Еще по теме, а обязательно нужно стирание типов с std::function? Может быть удастся обойтись шаблонной f():

template<typename G>
void f(G g)
{
    ....
    g();
}


А если нужно больше аргументов, воспользоваться std::bind:
void g1(int);
void g2(int, int);

f(std::bind(&g1, 1));
f(std::bind(&g2, 1, 2));
Re[7]: std::function, could not deduce template argument
От: _NN_ www.nemerleweb.com
Дата: 14.02.15 07:08
Оценка:
Здравствуйте, c-smile, Вы писали:

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


_NN>>Здравствуйте, c-smile, Вы писали:


CS>>>Слышишь эхо комбинаторного взрыва? Нет? А он есть...

CS>>>От 0 до 8-ми аргументов. Да по всем типам функций: member/free, const/non-const, throws/not-throws, volatile и не очень...

_NN>>И что с того ? Простой скрипт все нагенерирует.

_NN>>Коль нет вариадиков, хоть так извратиться.

CS>2**7 = 128 деклараций ... да ну нафиг.

Скрипт то генерирует , не вручную же =)

CS>Лучше уж люди руками напишут


Ну все таки разница есть между лямбдой и std::function.
Да и auto хочется везде использовать как только привыкаешь к удобству
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: std::function, could not deduce template argument
От: BulatZiganshin  
Дата: 14.02.15 09:26
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>void f(std::function<void(T)> g)

CS> auto func1 = [](int x) { std::cout << x << std::endl; };
CS> f(func1);

такой код не будет работать ни в каком c++ даже без второго определения f, поскольку лямбда и std::function — разные типы, и автоматом привести к нужному типу сквозь темплейт не получится. во всяком случае в vc2013/gcc49

вот так работает:

void f(std::function<void(int)> g)
    f(func1);

может, можно соорудить конвертор? типа такого:

template <typename T>
std::function<T> cvt(T &x) {return x;}

    auto func1 = cvt([](int x) { std::cout << x << std::endl; });
Люди, я люблю вас! Будьте бдительны!!!
Отредактировано 14.02.2015 9:39 BulatZiganshin . Предыдущая версия . Еще …
Отредактировано 14.02.2015 9:28 BulatZiganshin . Предыдущая версия .
Отредактировано 14.02.2015 9:28 BulatZiganshin . Предыдущая версия .
Re[8]: std::function, could not deduce template argument
От: c-smile Канада http://terrainformatica.com
Дата: 14.02.15 17:30
Оценка:
Здравствуйте, PM, Вы писали:

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


PM>>>Хотя, если доступен Boost, в нем кажется есть похожее: http://www.boost.org/doc/libs/1_57_0/libs/function_types/doc/html/index.html

CS>>Это для одного из headers моего SDK, требовать еще наличия boost совсем не comme il faut ни разу.

PM>Я бы отказался от поддержки старых компиляторов и требовал С++11


Не могу пока.

PM>Еще по теме, а обязательно нужно стирание типов с std::function? Может быть удастся обойтись шаблонной f()


Есть такой тип (variant, discriminated union)

class value 
{
public:
  value( int i );
  value( double f );
  value( string s );
  value( std::function<value(unsigned int argc, const value* argv)> func ); // value-function 

  template<typename T> T get() const;
};


И есть набор vfunc определений — конвертируют std::function в value-function

   // 
   template<typename R,typename P0>
      inline value vfunc( std::function<R(P0)> func )
      {
        return value([func](unsigned int argc, const value* argv) -> value { 
          R r = func(argc >= 1? argv[0].get<P0>(): P0() ); 
          return value(r); }); 
      }
    template<typename R,typename P0,typename P1>
      inline value vfunc( std::function<R(P0,P1)> func )
      {
        return value([func](unsigned int argc, const value* argv) -> value { 
          R r = func(argc >= 1? argv[0].get<P0>(): P0(),
                     argc >= 2? argv[1].get<P1>(): P1() ); 
          return value(r); }); 
      }

    ...


Это работает в принципе.

Но не для лямбд. Это вот не компилируется:

value local_func = vfunc( []{ int a, int b } { return a + b; } );


А это вот работает:

std::function<int(int,int)> t = []{ int a, int b } { return a + b; };
value local_func = vfunc( t );
Отредактировано 14.02.2015 17:35 c-smile . Предыдущая версия .
Re: std::function, could not deduce template argument
От: Константин Россия  
Дата: 14.02.15 19:18
Оценка: -1
Здравствуйте, c-smile, Вы писали:


CS>Есть вот такая конструкция


CS>
CS>template <typename T>
CS>void f(std::function<void(T)> g)

CS>template <typename T1, typename T2>
CS>void f(std::function<void(T1 t1,T2 t2)> g)

CS>int main(int argc, char* argv[])
CS>{
CS>    auto func1 = [](int x) { std::cout << x << std::endl; };
CS>    auto func2 = [](int x, int y) { std::cout << x << y << std::endl; };

CS>    f(func1);
CS>    f(func2);

CS>    return 0;
CS>}
CS>


Какая-то пессимизация на пустом месте. Вместо функторов которые ещё и отлично инлайнятся, всё гонится через тяжёлый std::function. Зачем???

template <G> void f1(G g) {...}
template <G> void f2(G g) {...}

auto func1 = [](int x) { std::cout << x << std::endl; };
auto func2 = [](int x, int y) { std::cout << x << y << std::endl; };
f1(func1);
f2(func2);
Re[2]: std::function, could not deduce template argument
От: BulatZiganshin  
Дата: 15.02.15 04:03
Оценка:
Здравствуйте, Константин, Вы писали:

К>template <G> void f1(G g) {...}

К>template <G> void f2(G g) {...}

а если f1 и f2 должны быть перегрузками одной функции?
Люди, я люблю вас! Будьте бдительны!!!
Re[2]: std::function, could not deduce template argument
От: jazzer Россия Skype: enerjazzer
Дата: 15.02.15 08:03
Оценка:
Здравствуйте, Константин, Вы писали:

К>Здравствуйте, c-smile, Вы писали:


К>Какая-то пессимизация на пустом месте. Вместо функторов которые ещё и отлично инлайнятся, всё гонится через тяжёлый std::function. Зачем???


У c-smile там фреймворк с колбеками, так что, я думаю, это для хранения оных, и в этом смысле std::function подходит лучше всего.
(Еще лучше подошел бы Boost.Signal, но c-smile не хочет тащить буст, за исключением того, что уже попало в std)
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.