template class template parameters

Jan 13, 2020 at 1:40pm
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 Jan 13, 2020 at 1:43pm
Jan 13, 2020 at 1:59pm
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;
Jan 13, 2020 at 2:14pm
> 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
};
Jan 13, 2020 at 5:04pm
Thanks, guys,
I hoped to keep class internals the same for flexibility, but maybe it will take some compromise.
Jan 13, 2020 at 11:42pm
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

Jan 14, 2020 at 6:51am
Awesome, thanks, man!
Topic archived. No new replies allowed.