C++ How to create a constant pointer to a function?

I want to have a class with a constant pointer to a function as a member. However, I'm instead creating functions with constant return values (a strange feature I just run into while debugging).

The troublesome declarations are:

// ...

template<typename T, typename ComparableValue>
class TimestampedValueHeap {
    public:
        TimestampedValueHeap(
            const ComparableValue (*)(const T&),
            const big_unsigned (*)(const T&)
        );

    protected:
        const ComparableValue (*getValue)(const T&);
        const big_unsigned (*getTimestamp)(const T&);
};

// ...

template<typename T, typename ComparableValue>
class TimestampedValueMinHeap : TimestampedValueHeap<T, ComparableValue> {
    public:
        TimestampedValueMinHeap(
            const ComparableValue (*)(const T&),
            const big_unsigned (*)(const T&)
        );
};

// ...

Here's the minimal WORKING example without const's. I'm using C++14.

#include <utility>

using namespace std;

typedef unsigned long long big_unsigned;

template <typename T, typename U>
T getFirst(const pair<T, U>& x) {
  return x.first;
}

template<typename T, typename U>
U getSecond(const pair<T, U>& x) {
    return x.second;
}

// ==================================================
// TimestampedValueHeap
// ==================================================

template<typename T, typename ComparableValue>
class TimestampedValueHeap {
    public:
        TimestampedValueHeap(
            ComparableValue (*)(const T&),
            big_unsigned (*)(const T&)
        );

    protected:
        ComparableValue (*getValue)(const T&);
        big_unsigned (*getTimestamp)(const T&);
};

template<typename T, typename ComparableValue>
TimestampedValueHeap<T, ComparableValue>::TimestampedValueHeap(
    ComparableValue (*getValue)(const T&),
    big_unsigned (*getTimestamp)(const T&)
): getValue(getValue), getTimestamp(getTimestamp) {
}

// ==================================================
// TimestampedValueMinHeap
// ==================================================

template<typename T, typename ComparableValue>
class TimestampedValueMinHeap : TimestampedValueHeap<T, ComparableValue> {
    public:
        TimestampedValueMinHeap(
            ComparableValue (*)(const T&),
            big_unsigned (*)(const T&)
        );
};

template<typename T, typename ComparableValue>
TimestampedValueMinHeap<T, ComparableValue>::TimestampedValueMinHeap(
    ComparableValue (*getValue)(const T&),
    big_unsigned (*getTimestamp)(const T&)
): TimestampedValueHeap<T, ComparableValue>::TimestampedValueHeap(getValue, getTimestamp) {
}

int main() {
    const TimestampedValueMinHeap<pair<int, big_unsigned>, int> minHeap(
        getFirst<int, big_unsigned>,
        getSecond<int, big_unsigned>
    );
    return 0;
}

Here's the BROKEN example with the added const's.

#include <utility>

using namespace std;

typedef unsigned long long big_unsigned;

template <typename T, typename U>
T getFirst(const pair<T, U>& x) {
  return x.first;
}

template<typename T, typename U>
U getSecond(const pair<T, U>& x) {
    return x.second;
}

// ==================================================
// TimestampedValueHeap
// ==================================================

template<typename T, typename ComparableValue>
class TimestampedValueHeap {
    public:
        TimestampedValueHeap(
            const ComparableValue (*)(const T&),
            const big_unsigned (*)(const T&)
        );

    protected:
        const ComparableValue (*getValue)(const T&);
        const big_unsigned (*getTimestamp)(const T&);
};

template<typename T, typename ComparableValue>
TimestampedValueHeap<T, ComparableValue>::TimestampedValueHeap(
    const ComparableValue (*getValue)(const T&),
    const big_unsigned (*getTimestamp)(const T&)
): getValue(getValue), getTimestamp(getTimestamp) {
}

// ==================================================
// TimestampedValueMinHeap
// ==================================================

template<typename T, typename ComparableValue>
class TimestampedValueMinHeap : TimestampedValueHeap<T, ComparableValue> {
    public:
        TimestampedValueMinHeap(
            const ComparableValue (*)(const T&),
            const big_unsigned (*)(const T&)
        );
};

template<typename T, typename ComparableValue>
TimestampedValueMinHeap<T, ComparableValue>::TimestampedValueMinHeap(
    const ComparableValue (*getValue)(const T&),
    const big_unsigned (*getTimestamp)(const T&)
): TimestampedValueHeap<T, ComparableValue>::TimestampedValueHeap(getValue, getTimestamp) {
}

int main() {
    const TimestampedValueMinHeap<pair<int, big_unsigned>, int> minHeap(
        getFirst<int, big_unsigned>,
        getSecond<int, big_unsigned>
    );
    return 0;
}

You should get a compilation error such as:

No matching constructor for initialization of 'const TimestampedValueMinHeap<pair<int, big_unsigned>, int>' (aka 'const TimestampedValueMinHeap<pair<int, unsigned long long>, int>')

However, it works if you simply cast the arguments.

// ...
int main() {
    const TimestampedValueMinHeap<pair<int, big_unsigned>, int> minHeap(
        (const int (*)(const pair<int, big_unsigned>&)) getFirst<int, big_unsigned>,
        (const big_unsigned (*)(const pair<int, big_unsigned>&)) getSecond<int, big_unsigned>
    );
    return 0;
}

Upvotes: 0

Views: 113

Answers (1)

alfC
alfC

Reputation: 16242

Try doing it in steps, it is more readable also,

        using getValue_ptr_type = ComparableValue (*)(const T&);
        using const_getValue_ptr_type = const getValue_ptr_type;
        const_getValue_ptr_type getValue;

OR use EAST const (my favorite)

        ComparableValue (* const getValue)(const T&);
        big_unsigned (* const getTimestamp)(const T&);

https://godbolt.org/z/z7P6P3sKz


NOTE: @MatthewM. rightly says that it is not a matter of EAST const or const WEST. This the only right way (for one liners).

east const

Upvotes: 3

Related Questions