4

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;
   });
Community
  • 1
  • 1
amin
  • 3,672
  • 5
  • 33
  • 61
  • 2
    Possible duplicate of [Overloading operator>> for lambdas](http://stackoverflow.com/questions/23591075/overloading-operator-for-lambdas) **Note:** [The mouse police never sleeps!](https://www.youtube.com/watch?v=3f9XiQgMDuw) (you might consider either editing, or deleteing your former question then) – πάντα ῥεῖ May 11 '14 at 16:24
  • I do not think the data extraction into a functor taking multiple field values is a good idea. –  May 11 '14 at 16:39
  • Also: The operator << does not distinguish between the SQL statement and input parameters (db << "SELECT *" << " FROM" << " table") –  May 11 '14 at 16:42
  • @DieterLücking I'm agree with you that my design is not the best ! but still i want to know how to implement it (if it is possible at all) . – amin May 11 '14 at 16:43
  • @DieterLücking the first << operator returns an intermediate class `database_bind` and i have overloaded the << operator on `database_bind` class too . – amin May 11 '14 at 16:44
  • @DieterLücking please take a look at github project (the link is in my question ) . – amin May 11 '14 at 16:46
  • @amin You might be interested in POCO::Data (http://pocoproject.org/docs/00200-DataUserManual.html) –  May 11 '14 at 16:49
  • http://stackoverflow.com/questions/7943525/is-it-possible-to-figure-out-the-parameter-type-and-return-type-of-a-lambda may be useful. – T.C. May 11 '14 at 16:55
  • @DieterLücking thanks, that is a great library. i have tried similar libraries before but eventually i came up writing my own version. and now i want to know the c++ syntax as much as i want to have a simple fast wrapper around sqlite C api ! – amin May 11 '14 at 16:55
  • I feel the need to mention the **Law of Lambda Banality**: *if your interface cares about lambdas, it's wrong*. It is alternatively phrased as "*lambdas are not special*", meaning that lambdas are just callable objects like any other and from the point of view of someone writing a function that accepts them, they are indistinguishable. – R. Martinho Fernandes May 14 '14 at 21:05
  • @R.MartinhoFernandes Re :`lambdas are not special` : of course they are ! why not to care about them when even the language does . – amin May 15 '14 at 13:07
  • I think you stopped reading at the wrong point: ", meaning that lambdas are just callable objects like any other and from the point of view of someone writing a function that accepts them, they are indistinguishable." – R. Martinho Fernandes May 15 '14 at 13:08

2 Answers2

0

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; });
}
Nikos Athanasiou
  • 29,616
  • 15
  • 87
  • 153
-1

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; };
   }
Community
  • 1
  • 1
amin
  • 3,672
  • 5
  • 33
  • 61