I have asked a similar question before overloading operator >> for lambdas
But i did not explained what i really wanted .
I am writing a simple wrapper around sqlite3 C api .
this is my project on github => sqlite modern cpp
I want to overload the >> operator for lambdas.
I want the fallowing code to work :
database db("dbfile.db");
db << "select age,name,weight from user where age > ? ;"
<< 18
>> [&](int age, string name, double weight) {
cout << age << ' ' << name << ' ' << weight << endl;
};
I want the idea! that is why i abstracted the question in my previous question.
I have a database_bind
class which is returned by the '<<' operator ,
i want to be able to overload >> operator on database_bind
class
for lambdas with different number of arguments.
Currently i'm supporting this syntax :
db << "select age,name,weight from user where age > ? ;"
<< 18
>> function<void(int,string,double)>([&](int age, string name, double weight) {
cout << age << ' ' << name << ' ' << weight << endl;
});
What you need is a retrospective cast. A way to compose a correct function object type from passing it only a lambda (and nothing else, no template arguments, not return type specification).
A way to do it without dependencies from other libraries would be the following
#include <iostream>
#include<functional>
#include<vector>
using namespace std;
template<typename T>
struct memfun_type
{
using type = void;
};
template<typename Ret, typename Class, typename... Args>
struct memfun_type<Ret(Class::*)(Args...) const>
{
using type = std::function<Ret(Args...)>;
};
template<typename F>
typename memfun_type<decltype(&F::operator())>::type
FFL(F const &func)
{ // Function from lambda !
return func;
}
Then you can be aware of your lambas' return type and write the following
int main()
{
database_bind dbb;
dbb >> FFL([](int i, string s) { cout << i << ' ' << s << endl; });
dbb >> FFL([](int i) { cout << i << endl; });
dbb >> FFL([](string s,double d) { cout << s << ' ' << d << endl; });
}
Based on this question
i wrote the fallowing code.
I did not completely understood function_traits
! but i was able to
overload the >> operator for lambdas with different number of arguments .
I know it's not the best possible solution , but i wrote it so someone can take it as a starting point ( a variadic template implementation will be awesome !) .
#include<iostream>
#include<string>
#include<tuple>
using namespace std;
template <typename T>
struct function_traits
: public function_traits<decltype(&T::operator())>
{};
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
// we specialize for pointers to member function
{
enum { arity = sizeof...(Args) };
// arity is the number of arguments.
typedef ReturnType result_type;
template <size_t i>
struct arg
{
typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
// the i-th argument is equivalent to the i-th tuple element of a tuple
// composed of those arguments.
};
};
// a place holder class
class database_bind {};
template<int N>
class A {
template<typename F>
static void run(F l);
};
template<>
struct A<1> {
template<typename F>
static void run(F l) {
typedef function_traits<decltype(l)> traits;
typedef typename traits::arg<0>::type type_1;
type_1 col_1;
get_from_db(0, col_1);
l(col_1);
}
};
template<>
struct A<2> {
template<typename F>
static void run(F l) {
typedef function_traits<decltype(l)> traits;
typedef typename traits::arg<0>::type type_1;
typedef typename traits::arg<1>::type type_2;
type_1 col_1;
type_2 col_2;
get_from_db(0, col_1);
get_from_db(1, col_2);
l(col_1, col_2);
}
};
void get_from_db(int col_inx, string& str) { str = "string"; }
void get_from_db(int col_inx, int& i) {i = 123;}
void get_from_db(int col_inx, double& d) { d = 123.456; }
template<typename F>
void operator>>(database_bind dbb, F l)
{
typedef function_traits<decltype(l)> traits;
A<traits::arity>::run(l);
}
And finally :
int main() {
database_bind dbb;
dbb >> [](int i, string s) { cout << i << ' ' << s << endl; };
dbb >> [](int i) { cout << i << endl; };
dbb >> [](string s,double d) { cout << s << ' ' << d << endl; };
}