template class template parameters

Hi guys!

I am experimenting with a template Binary_Heap class,
initially like this:

1
2
3
4
5
6
7
8
template <class T> bool comp_min(const T& left, const T& right) {
	return left > right; // min heap
}
// and
template <class T, bool importance(const T&, const T&)> class Binary_Heap{...};

// in main
Binary_Heap<int, comp_min<int> > bh;


It works as expected,
but I decided to change it a bit to use func pointer as template argument:

1
2
3
4
template <class T, bool(*importance)(const T&, const T&)> class Binary_heap{...}

// in main
Binary_Heap<int, &comp_min<int> > bh;


It also works as expected,
but the problem came when I tried to pass lambda/functor comparators to func pointer template argument.

Here is the lambda:

1
2
3
4
template <class T>
auto get_min = [](const T& left, const T& right)->bool const {
	return left > right; // min heap
};


and here is the functor class:

1
2
3
4
5
6
7
template < class T>
class tell_min {
    public:
    bool operator()(const T& left, const T& right) {
        return left > right;
    }
};


Did a lot of experimenting, but not success so far,
would appreciate some hints/ directions how to approach proper implementation.

Thanks!
K.

Last edited on
duck typing, if it has an operator() that receives two object convertible to T, and that returns something that may be interpreted as a bool, then all's good.
template <class T, class Comparator> Binary_Heap;
> but the problem came when I tried to pass lambda

Closure types (the type of lambda expressions) are not DefaultConstructible.

Write a constructor which allows us to provide a comparison object. For example:

1
2
3
4
5
6
7
8
9
template < typename T, typename CMP > struct binary_heap
{
     // use a default constructed object if no argument is provided
     explicit binary_heap( const CMP& cmp = {} ) : cmp_fn(cmp) {} 
     
    // ...

     CMP cmp_fn ; // use cmp_fn(x,y) for comparison
};
Thanks, guys,
I hoped to keep class internals the same for flexibility, but maybe it will take some compromise.
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
#include <algorithm>
#include <initializer_list>
#include <iostream>
#include <vector>


template <typename T, typename Compare> struct BinaryHeap;

template <typename T, typename Compare>
std::ostream& operator<< ( std::ostream& os, const BinaryHeap<T, Compare>& rhs );


template <typename T>
struct Comp {
    bool operator()(const T& lhs, const T& rhs) const;
};


template <typename T>
bool Comp<T>::operator()(const T& lhs, const T& rhs) const
{
    return lhs > rhs;
}


template <typename T, typename Compare = std::greater<T>>
struct BinaryHeap {
    std::vector<T> v;

    explicit BinaryHeap(std::initializer_list<T> v_arg);

//friend:
    friend std::ostream& operator<< <> ( std::ostream& os,
                                         const BinaryHeap<T, Compare>& rhs );
};


template <typename T, typename Compare>
BinaryHeap<T, Compare>::BinaryHeap(std::initializer_list<T> v_arg)
    : v { v_arg }
{
    std::sort(v.begin(), v.end(), Compare());
}


template <typename T, typename Compare>
std::ostream& operator<< ( std::ostream& os, const BinaryHeap<T, Compare>& rhs )
{
    for ( const auto& e : rhs.v ) {
        os << e << ' ';
    }
    return os;
}


int main()
{
    BinaryHeap<int> bh_1 { 3, 5, 1, 4, 2 };
    std::cout << bh_1 << '\n';

    BinaryHeap<int, Comp<int>> bh_2 { 3, 5, 1, 4, 2 };
    std::cout << bh_2 << '\n';

    auto l_f { [](auto a, decltype(a) b) -> bool { return a > b; } };
    BinaryHeap<int, decltype(l_f)> bh_3( { 3, 5, 1, 4, 2 } );
    std::cout << bh_3 << '\n';
}


Output:
5 4 3 2 1
5 4 3 2 1
5 4 3 2 1

Awesome, thanks, man!
Registered users can post here. Sign in or register to post.