CS>Но это смысла не имеет так как у тебя три переменные с одним именем.
CS>Или я чего-то не понял концептуально?
ага. у тебя template<class X> не там, он должен быть внутри, а не снаружи. Эквивалентный функциональный объект выглядит как-то так:
// template<class X> -- не здесь!struct PrintX
{
template<class X> // вот он где!void operator()(X x) { cout << x << endl; };
};
Если бы он был снаружи — твои соображения были бы верны.
ЗЫ Именно так работала и Boost.Lambda. Ты мог одно и то же имя (как а выше) вызывать с разными аргументами.
Добро пожаловать в С++14! (если ты пропустил вечеринку с Boost.Lambda)
Здравствуйте, c-smile, Вы писали:
PM>>Еще по теме, а обязательно нужно стирание типов с std::function? Может быть удастся обойтись шаблонной f()
[здесь было объяснение]
А, это видимо реализация xcall в Sciter. Тогда да, тут нужно стирание типов. Как уже написал выше Булат, std::function и лямбды имеют разный тип. Так что нужно нечто, преобразующее лямбду в std::function, и без поддержки variadic templates придется писать набор перегруженных функций для разумного кол-ва аргументов, тут без вариантов.
Идея в том, чтобы в function_traits для лямбды хранить тип соответствующей std::function. Вот специализации function_traits для лямбд с 0..2 аргументами:
Здравствуйте, BulatZiganshin, Вы писали:
BZ>Здравствуйте, jazzer, Вы писали:
J>>>>В std::function<void(int)> var = []{} ты просишь компилятор проверить, можно ли использовать int (который ты своими руками написал). J>>>>А исходная задача — вывести этот int.
J>>про то, как это может быть в конструкторе, я уже писал тут
.
BZ>я не вижу здесь никакой разницы с шаблонным вызовом функции. ты не мог бы привести этот конструктор?
ну типа так (пишу в браузере):
template<class F> // F - это void(int)struct function
{
F f;
using argT = traits<F>....; // int
// объект-лямбда объект-аргумент типа argTtemplate<class L, class = decltype( ( *(L*)nullptr )( *(argT*)nullptr ) )> // SFINAE
function(L lambda): f{lambda} {}
//... другие конструкторы
};
этот конструктор скомпилируется, только если вызов lambda с аргументом типа argT валиден.
Здравствуйте, BulatZiganshin, Вы писали:
J>> // объект-лямбда объект-аргумент типа argT J>> template<class L, class = decltype( ( *(L*)nullptr )( *(argT*)nullptr ) )> // SFINAE BZ>так SFINAE точно так же к вызовам функций применимо, в чём разница?
Разница в том, что здесь используется argT, пришедший через аргумент шаблона function.
Если в обычный шаблон функции также передавать дополнительный шаблонный параметр с типом сигнатуры, то будет работать и там.
Re[10]: std::function, could not deduce template argument
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
Здравствуйте, c-smile, Вы писали:
CS>Как бы исхитриться? CS>Ну или получить количество параметров std::function wrapper и их типы. Знаю как это сделать с пом. variadic templates, но на руках VS 2010, там этого нет.
Ну если есть решение на вариадках, то несложно нагенерировать специализации.
Здравствуйте, _NN_, Вы писали:
_NN>Здравствуйте, c-smile, Вы писали:
CS>>Как бы исхитриться? CS>>Ну или получить количество параметров std::function wrapper и их типы. Знаю как это сделать с пом. variadic templates, но на руках VS 2010, там этого нет.
_NN>Ну если есть решение на вариадках, то несложно нагенерировать специализации.
_NN>Вроде как decltype поддерживается в VS 2010.
А как decltype тут поможет?
Re[2]: std::function, could not deduce template argument
Здравствуйте, 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
Здравствуйте, c-smile, Вы писали:
CS>Ну или получить количество параметров std::function wrapper и их типы. Знаю как это сделать с пом. variadic templates, но на руках VS 2010, там этого нет.
Здравствуйте, 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
Здравствуйте, c-smile, Вы писали:
CS>Слышишь эхо комбинаторного взрыва? Нет? А он есть... CS>От 0 до 8-ми аргументов. Да по всем типам функций: member/free, const/non-const, throws/not-throws, volatile и не очень...
И что с того ? Простой скрипт все нагенерирует.
Коль нет вариадиков, хоть так извратиться.
Здравствуйте, c-smile, Вы писали:
_NN>>А в чем проблема сгенерировать необходимое количество специализаций вручную ?
CS>Слышишь эхо комбинаторного взрыва? Нет? А он есть... CS>От 0 до 8-ми аргументов. Да по всем типам функций: member/free, const/non-const, throws/not-throws, volatile и не очень...
Здравствуйте, _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, Вы писали:
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 хочется везде использовать как только привыкаешь к удобству
Здравствуйте, 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; });
Здравствуйте, 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 );
Здравствуйте, Константин, Вы писали:
К>Здравствуйте, c-smile, Вы писали:
К>Какая-то пессимизация на пустом месте. Вместо функторов которые ещё и отлично инлайнятся, всё гонится через тяжёлый std::function. Зачем???
У c-smile там фреймворк с колбеками, так что, я думаю, это для хранения оных, и в этом смысле std::function подходит лучше всего.
(Еще лучше подошел бы Boost.Signal, но c-smile не хочет тащить буст, за исключением того, что уже попало в std)
Здравствуйте, c-smile, Вы писали: CS>Есть вот такая конструкция
вот так заработало с gcc49, но не msvc2013:
Скрытый текст
#include <functional>
#include <iostream>
template <typename T>
void f(std::function<void(T)> g)
{
std::cout << "1 arg:";
g(-1);
}
template <typename T>
void f(void g(T))
{
std::cout << "1 arg:";
g(1);
}
template <typename T1, typename T2>
void f(void g(T1,T2))
{
std::cout << "2 args:";
g(11,22);
}
template <typename T1, typename T2, typename T3>
void f(void g(T1,T2,T3))
{
std::cout << "3 args:";
g(111,222,333);
}
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; };
auto func3 = [](int x, int y, int z) { std::cout << x << y << z << std::endl; };
f(+func1);
f(+func2);
f(+func3);
return 0;
}
ключевые моменты — "+func1" и "void f(void g(T1,T2))" в дополнение к перегрузке по std::function. сообщение msvc об ошибке тоже достойно увековечения:
lambda_as_std_function2.cpp(27) : error C2593: 'operator +' is ambiguous
could be 'built-in C++ operator+(void (__cdecl *)(int))'
or 'built-in C++ operator+(void (__vectorcall *)(int))'
while trying to match the argument list '(main::<lambda_c762786ee855352b046bdd0fba86f419>)'
по большому счёту, я знаю библиотеки которые принимают шаблонные лямбды на входе (включая std), значит решение есть. вот что я вижу в одной из них:
Скрытый текст
использование:
/**
* Same as the other writeFunction, except that the template parameter is automatically detected
* This only works if the data is either a native function pointer, or contains one operator() (this is the case for lambdas)
*/template<typename... TData>
void writeFunction(TData&&... data) noexcept {
static_assert(sizeof...(TData) >= 2, "You must pass at least a variable name and a value to writeFunction");
typedef typename std::decay<typename std::tuple_element<sizeof...(TData) - 1,std::tuple<TData...>>::type>::type
RealDataType;
typedef typename FunctionTypeDetector<RealDataType>::type
DetectedFunctionType;
return writeFunction<DetectedFunctionType>(std::forward<TData>(data)...);
}
определение:
// this structure takes a pointer to a member function type and returns the base function typetemplate<typename TType>
struct RemoveMemberPointerFunction { typedef void type; }; // required because of a compiler bug
// this structure takes any object and detects its function typetemplate<typename TObjectType>
struct FunctionTypeDetector { typedef typename RemoveMemberPointerFunction<decltype(&std::decay<TObjectType>::type::operator())>::type type; };
// this structure takes any object and detects its function typetemplate<typename TRetValue, typename... TParameters>
struct LuaContext::FunctionTypeDetector<TRetValue (TParameters...)> { typedef TRetValue type(TParameters...); };
template<typename TObjectType>
struct LuaContext::FunctionTypeDetector<TObjectType*> { typedef typename FunctionTypeDetector<TObjectType>::type type; };
// this structure takes a pointer to a member function type and returns the base function typetemplate<typename TType, typename TRetValue, typename... TParameters>
struct LuaContext::RemoveMemberPointerFunction<TRetValue (TType::*)(TParameters...)> { typedef TRetValue type(TParameters...); };
template<typename TType, typename TRetValue, typename... TParameters>
struct LuaContext::RemoveMemberPointerFunction<TRetValue (TType::*)(TParameters...) const> { typedef TRetValue type(TParameters...); };
template<typename TType, typename TRetValue, typename... TParameters>
struct LuaContext::RemoveMemberPointerFunction<TRetValue (TType::*)(TParameters...) volatile> { typedef TRetValue type(TParameters...); };
template<typename TType, typename TRetValue, typename... TParameters>
struct LuaContext::RemoveMemberPointerFunction<TRetValue (TType::*)(TParameters...) const volatile> { typedef TRetValue type(TParameters...); };
Люди, я люблю вас! Будьте бдительны!!!
Re[3]: std::function, could not deduce template argument
Здравствуйте, jazzer, Вы писали:
J>Здравствуйте, Константин, Вы писали:
К>>Здравствуйте, c-smile, Вы писали:
К>>Какая-то пессимизация на пустом месте. Вместо функторов которые ещё и отлично инлайнятся, всё гонится через тяжёлый std::function. Зачем???
J>У c-smile там фреймворк с колбеками, так что, я думаю, это для хранения оных, и в этом смысле std::function подходит лучше всего.
Это для передачи native functions в script. Можно считать что это callbacks в каком-то роде.
Решение, кстати, для любого script integration может быть полезно.
Скажем в script (JavaScript, TIScript) я могу написать такое:
function getRecordset( params ) {
var nrs = ...; // opening recordset somehowfunction nextRecord() { gets next record from nrs }
function prevRecord() { gets prev record from nrs }
// returns public API of the recordset, hides nrs completely: return {
next: nextRecord,
prev: prevRecord
...
};
}
И использование
var rs = getRecordset("shoppingCartData");
while(var record = rs.next()) {
...
}
getRecordset может быть native (С++) функция
value getRecordset() {
std::shared_ptr<db::recordset> nrs = ....
std::function<value()> nextRecord = [nrs]() -> value {
... return next record as key/value map
... or 'undefined' as value()
};
std::function<value()> prevRecord = [nrs]() -> value { ... };
value r;
r.set_item("next", vfunc(nextRecord) );
r.set_item("prev", vfunc(prevRecord) );
return r;
}
Это вот выше уже и так работает. Просто хотелось еще и auto разрешить.
Вот интересно, C++ компилятор же как-то проверяет типы слева и справа здесь:
std::function<...> var = ...lambda...;
т.е. им можно, а нам не нельзя ?
Re[4]: std::function, could not deduce template argument
Здравствуйте, c-smile, Вы писали:
CS>Вот интересно, C++ компилятор же как-то проверяет типы слева и справа здесь: CS>
CS> std::function<...> var = ...lambda...;
CS>
CS>т.е. им можно, а нам не нельзя ?
Ну он же тут проверяет конкретные указанные тобой типы аргументов, а не выводит их.
В этом смысле достаточно SFINAE в конструкторе по decltype(lambda(int(),int())) — в смысле, проверить, что для этих типов код компилируется (заодно и шаблонные автолямбды так же накрываются — а у них ведь тип аргумента в принципе невозможно вывести).
(Правда, не уверен, что это именно так работает в вц2010, да и знать не хочу, если честно, я не палеонтолог в душе Вполне возможно, что они у себя тупо недокументированным интерфейсом пользуются)
Здравствуйте, jazzer, Вы писали:
J>В этом смысле достаточно SFINAE в конструкторе по decltype(lambda(int(),int())) — в смысле, проверить, что для этих типов код компилируется (заодно и шаблонные автолямбды так же накрываются — а у них ведь тип аргумента в принципе невозможно вывести).
Если lambda это некий уникальный тип то почему бы не сделать
Здравствуйте, c-smile, Вы писали:
CS>Здравствуйте, jazzer, Вы писали:
J>>В этом смысле достаточно SFINAE в конструкторе по decltype(lambda(int(),int())) — в смысле, проверить, что для этих типов код компилируется (заодно и шаблонные автолямбды так же накрываются — а у них ведь тип аргумента в принципе невозможно вывести).
CS>Если lambda это некий уникальный тип то почему бы не сделать
CS>
CS>auto foo = [](int a,int b) { return a + b; };
CS>decltype(foo)::function_type -> std::function<int(int,int)>
CS>
CS>Компайлер ведь этой всей информацией обладает...
это возможно только в самом тривиальном случае.
как насчет вот этого?
auto a = [](auto x){ cout << x << endl; };
a(1);
a(3.14);
a("asd");
std::function<void(int)> fi{a};
std::function<void(double)> fd{a};
std::function<void(const char*)> fs{a};
fi(1);
fd(3.14);
fs("asd");
Какой function_type должен быть у а?
как насчет вот этого?
auto b = [](double x){ cout << x << endl; };
std::function<void(int)> fb{b};
fb(3.14); // напечатает 3auto c = [](int x){ cout << x << endl; };
std::function<void(double)> fc{c};
fc(3.14); // тоже напечатает 3
ты можешь спросить компилятор: "Можно ли привести лямбду к std::function конкретного типа?", но не спросить: "А дай мне все std::function, которые можно инициализировать из этой лямбды".
CS>>Или я чего-то не понял концептуально?
J>ага. у тебя template<class X> не там, он должен быть внутри, а не снаружи. Эквивалентный функциональный объект выглядит как-то так: J>
J>// template<class X> -- не здесь!
J>struct PrintX
J>{
J> template<class X> // вот он где!
J> void operator()(X x) { cout << x << endl; };
J>};
J>
J>Если бы он был снаружи — твои соображения были бы верны.
Зашибись, но как это работает в случае capturing lambda:
?
J>ЗЫ Именно так работала и Boost.Lambda. Ты мог одно и то же имя (как а выше) вызывать с разными аргументами. J>Добро пожаловать в С++14! (если ты пропустил вечеринку с Boost.Lambda)
С++14 ... Тут за счастье полную поддержку С++11 поиметь хотя бы.
Добро пожаловать в мир practical programming
Re[10]: std::function, could not deduce template argument
Естественно, строчка lambda("hello"); не скомпилируется.
CS>С++14 ... Тут за счастье полную поддержку С++11 поиметь хотя бы. CS>Добро пожаловать в мир practical programming
Да я тоже на С++98 на работе сижу, все никак не переедем
Здравствуйте, jazzer, Вы писали:
CS>> std::function<...> var = ...lambda...;
J>Ну он же тут проверяет конкретные указанные тобой типы аргументов, а не выводит их.
насколько я понимаю, тут срабатывает шаблонный конструктор, так что задача ровно та же самая
Люди, я люблю вас! Будьте бдительны!!!
Re[6]: std::function, could not deduce template argument
Здравствуйте, BulatZiganshin, Вы писали:
BZ>Здравствуйте, jazzer, Вы писали: CS>>> std::function<...> var = ...lambda...; J>>Ну он же тут проверяет конкретные указанные тобой типы аргументов, а не выводит их.
BZ>насколько я понимаю, тут срабатывает шаблонный конструктор, так что задача ровно та же самая
Нет, не та же.
В std::function<void(int)> var = []{} ты просишь компилятор проверить, можно ли использовать int (который ты своими руками написал).
А исходная задача — вывести этот int.
CS>auto foo = [](int a,int b) { return a + b; };
CS>decltype(foo)::function_type -> std::function<int(int,int)>
CS>
CS>Компайлер ведь этой всей информацией обладает...
Такую метафункцию (принимающую тип лямбды и возвращающую соответствующий тип std::function) можно сделать вручную — как уже показали выше через decltype
(+ эмуляция variadic'ов на MSVC2010).
Но, как уже заметили, есть ограничение — это полиморфные лямбды (которых нет в MSVC2010) и функциональные объекты с шаблонным либо перегруженным operator().
Re[7]: std::function, could not deduce template argument
Здравствуйте, jazzer, Вы писали:
J>В std::function<void(int)> var = []{} ты просишь компилятор проверить, можно ли использовать int (который ты своими руками написал). J>А исходная задача — вывести этот int.
это если std::function встроен в компилятор. я предполагаю, что он написан в обычном заголовочном файле и эта строка обрабатывается шаблонным конструктором. иными словами, напиши эквивалентный std::function тип, чтобы он такое принимал
Люди, я люблю вас! Будьте бдительны!!!
Re[8]: std::function, could not deduce template argument
Здравствуйте, BulatZiganshin, Вы писали:
BZ>Здравствуйте, jazzer, Вы писали:
J>>В std::function<void(int)> var = []{} ты просишь компилятор проверить, можно ли использовать int (который ты своими руками написал). J>>А исходная задача — вывести этот int.
BZ>это если std::function встроен в компилятор. я предполагаю, что он написан в обычном заголовочном файле и эта строка обрабатывается шаблонным конструктором. иными словами, напиши эквивалентный std::function тип, чтобы он такое принимал
про то, как это может быть в конструкторе, я уже писал тут
Здравствуйте, jazzer, Вы писали:
J>>>В std::function<void(int)> var = []{} ты просишь компилятор проверить, можно ли использовать int (который ты своими руками написал). J>>>А исходная задача — вывести этот int.
J>про то, как это может быть в конструкторе, я уже писал тут