Reputation: 75
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
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).
Upvotes: 3