Binding a method of a template class

I've got a database with two types of items (ItemA and ItemB) stored in it. I want the database to perform a kind of operation on either ItemA or ItemB. The operation should be executed on all items by object of OperationExecutor used by Database. Also I want the operation to be executed by OperationExecutor in a parallel thread. Therefore I want to use a std::bind to create a std::function<void()> to pass it as a thread's function. Unfortunately the bind is not compiling. What is wrong with it, how should it be done (if possible)?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <iostream>
#include <functional>
#include <thread>
#include <vector>

enum EItemType {
    EItemType_A = 1,
    EItemType_B = 2
};

class Item;

class Operation {
public:
    virtual ~Operation() = default;

    virtual EItemType type() const = 0;
    virtual void handle(Item&) = 0;
};

template<typename TIter>
class OperationExecutor {
public:
    void execute(Operation& oper, TIter first, TIter last) {
        // !!!! here is the issue located !!!!!
        std::function<void()> func = std::bind<void>(
                &OperationExecutor<TIter>::executeImpl,
                std::ref(*this), oper, first, last);
        thread_ = std::thread(func);
        thread_.join();
    }

private:
    void executeImpl(Operation& oper, TIter first, TIter last) {
        for (TIter it = first; it != last; ++it) {
             oper.handle(*it);
        }
    }

private:
    std::thread thread_;
};

struct Item {
};

struct ItemA : public Item {
    ItemA(int id) : id(id) {
    }

    int id;
};

struct ItemB : public Item {
    ItemB(int id) : id(id) {
    }

    int id;
};

class Database {
public:
    void exec(Operation& oper) {
        if (oper.type() == EItemType_A) {
            OperationExecutor<DatabaseA::iterator> executor;
            executor.execute(oper, itemsA.begin(), itemsA.end());
        }
 //       else if (oper.type() == EItemType_B) {
 //           OperationExecutor<DatabaseB::iterator> executor;
 //           executor.execute(oper, itemsB.begin(), itemsB.end());
 //       }
    }

    typedef std::vector<ItemA> DatabaseA;
    typedef std::vector<ItemB> DatabaseB;

    DatabaseA itemsA;
    DatabaseB itemsB;    
};

int main() {
    Database database;
    database.itemsA.push_back(ItemA(1));
    database.itemsA.push_back(ItemA(2));
    database.itemsA.push_back(ItemA(3));
    database.itemsA.push_back(ItemA(4));

    database.itemsB.push_back(ItemB(100));
    database.itemsB.push_back(ItemB(101));
    database.itemsB.push_back(ItemB(102));
    database.itemsB.push_back(ItemB(103));
}


compilation: g++ -std=c++11 -pthread test.cpp


In file included from test.cpp:2:0:
/usr/include/c++/4.9/functional: In instantiation of ‘struct std::_Bindres_helper<void, void (OperationExecutor<__gnu_cxx::__normal_iterator<ItemA*, std::vector<ItemA> > >::*)(Operation&, __gnu_cxx::__normal_iterator<ItemA*, std::vector<ItemA> >, __gnu_cxx::__normal_iterator<ItemA*, std::vector<ItemA> >), std::reference_wrapper<OperationExecutor<__gnu_cxx::__normal_iterator<ItemA*, std::vector<ItemA, std::allocator<ItemA> > > > >, Operation&, __gnu_cxx::__normal_iterator<ItemA*, std::vector<ItemA, std::allocator<ItemA> > >&, __gnu_cxx::__normal_iterator<ItemA*, std::vector<ItemA, std::allocator<ItemA> > >&>’:
/usr/include/c++/4.9/functional:1650:5:   required by substitution of ‘template<class _Result, class _Func, class ... _BoundArgs> typename std::_Bindres_helper<_Result, _Func, _BoundArgs>::type std::bind(_Func&&, _BoundArgs&& ...) [with _Result = void; _Func = void (OperationExecutor<__gnu_cxx::__normal_iterator<ItemA*, std::vector<ItemA> > >::*)(Operation&, __gnu_cxx::__normal_iterator<ItemA*, std::vector<ItemA> >, __gnu_cxx::__normal_iterator<ItemA*, std::vector<ItemA> >); _BoundArgs = {std::reference_wrapper<OperationExecutor<__gnu_cxx::__normal_iterator<ItemA*, std::vector<ItemA, std::allocator<ItemA> > > > >, Operation&, __gnu_cxx::__normal_iterator<ItemA*, std::vector<ItemA, std::allocator<ItemA> > >&, __gnu_cxx::__normal_iterator<ItemA*, std::vector<ItemA, std::allocator<ItemA> > >&}]’
test.cpp:27:51:   required from ‘void OperationExecutor<TIter>::execute(Operation&, TIter, TIter) [with TIter = __gnu_cxx::__normal_iterator<ItemA*, std::vector<ItemA> >]’
test.cpp:65:64:   required from here
/usr/include/c++/4.9/functional:1640:2: error: invalid abstract parameter type ‘Operation’
  type;
  ^
test.cpp:13:7: note:   because the following virtual functions are pure within ‘Operation’:
 class Operation {
       ^
test.cpp:17:23: note: 	virtual EItemType Operation::type() const
     virtual EItemType type() const = 0;
                       ^
test.cpp:18:18: note: 	virtual void Operation::handle(Item&)
     virtual void handle(Item&) = 0;
                  ^
test.cpp: In instantiation of ‘void OperationExecutor<TIter>::execute(Operation&, TIter, TIter) [with TIter = __gnu_cxx::__normal_iterator<ItemA*, std::vector<ItemA> >]’:
test.cpp:65:64:   required from here
test.cpp:27:51: error: no matching function for call to ‘bind(void (OperationExecutor<__gnu_cxx::__normal_iterator<ItemA*, std::vector<ItemA> > >::*)(Operation&, __gnu_cxx::__normal_iterator<ItemA*, std::vector<ItemA> >, __gnu_cxx::__normal_iterator<ItemA*, std::vector<ItemA> >), std::reference_wrapper<OperationExecutor<__gnu_cxx::__normal_iterator<ItemA*, std::vector<ItemA> > > >, Operation&, __gnu_cxx::__normal_iterator<ItemA*, std::vector<ItemA> >&, __gnu_cxx::__normal_iterator<ItemA*, std::vector<ItemA> >&)’
                 std::ref(*this), oper, first, last);
                                                   ^
test.cpp:27:51: note: candidates are:
In file included from test.cpp:2:0:
/usr/include/c++/4.9/functional:1623:5: note: template<class _Func, class ... _BoundArgs> typename std::_Bind_helper<std::__or_<std::is_integral<typename std::decay<_Tp>::type>, std::is_enum<typename std::decay<_Tp>::type> >::value, _Func, _BoundArgs ...>::type std::bind(_Func&&, _BoundArgs&& ...)
     bind(_Func&& __f, _BoundArgs&&... __args)
     ^
/usr/include/c++/4.9/functional:1623:5: note:   template argument deduction/substitution failed:
/usr/include/c++/4.9/functional: In substitution of ‘template<class _Func, class ... _BoundArgs> typename std::_Bind_helper<std::__or_<std::is_integral<typename std::decay<_Tp>::type>, std::is_enum<typename std::decay<_Tp>::type> >::value, _Func, _BoundArgs ...>::type std::bind(_Func&&, _BoundArgs&& ...) [with _Func = void; _BoundArgs = {}]’:
test.cpp:27:51:   required from ‘void OperationExecutor<TIter>::execute(Operation&, TIter, TIter) [with TIter = __gnu_cxx::__normal_iterator<ItemA*, std::vector<ItemA> >]’
test.cpp:65:64:   required from here
/usr/include/c++/4.9/functional:1623:5: error: forming reference to void
test.cpp: In instantiation of ‘void OperationExecutor<TIter>::execute(Operation&, TIter, TIter) [with TIter = __gnu_cxx::__normal_iterator<ItemA*, std::vector<ItemA> >]’:
test.cpp:65:64:   required from here
/usr/include/c++/4.9/functional:1650:5: note: template<class _Result, class _Func, class ... _BoundArgs> typename std::_Bindres_helper<_Result, _Func, _BoundArgs>::type std::bind(_Func&&, _BoundArgs&& ...)
     bind(_Func&& __f, _BoundArgs&&... __args)
     ^
/usr/include/c++/4.9/functional:1650:5: note:   substitution of deduced template arguments resulted in errors seen above
http://en.cppreference.com/w/cpp/utility/functional/bind
The arguments to bind are copied or moved, and are never passed by reference unless wrapped in std::ref or std::cref.
Topic archived. No new replies allowed.