I want in my code has compile-time checking, which ensures that the class overloads the operator ()that the operator receives the parameters const char *and size_tas parameters and that the return type is an unsigned integer.
I tried several code snippets taken from StackOverflow, but I am not satisfied with the solution I wrote:
#include <type_traits>
#include <cstdint>
#include <iostream>
#include <memory>
template<class>
struct sfinae_true : std::true_type{};
namespace detail{
template<class T>
static auto test(int)
-> sfinae_true<decltype(std::declval<T>()(static_cast<const char *>(nullptr), static_cast<size_t>(0u)))>;
template<class>
static auto test(long) -> std::false_type;
}
template<class T>
struct is_functor : decltype(detail::test<T>(0)){ };
template <typename T, typename HashFn,
typename std::enable_if<std::is_unsigned<T>::value, int>::type = 0>
struct Calculation {
Calculation() {
static_assert(is_functor<HashFn>(), "BAD signature");
typedef typename std::result_of<decltype(&HashFn::operator())(HashFn, const char *, size_t)>::type return_type;
static_assert(std::is_unsigned<return_type>::value, "BAD return type");
}
T output() {
return static_cast<T>(HashFn()(nullptr, 10));
}
};
struct Hash {
uint32_t operator ()(const char *buffer, size_t n) const {
return 65;
}
};
int main() {
Calculation<uint64_t, Hash> c;
c.output();
}
Sorry for the length of the code, I tried to keep it as small as possible.
Here's what I don't like about my code:
If I replace intwith size_tin the parameter list when the operator is overloaded (), no error occurs during compilation, because it size_tcan be implicitly discarded by int.
(, const ), . , , , .
rty.cpp: In instantiation of ‘Calculation<T, HashFn, <anonymous> >::Calculation() [with T = long unsigned int; HashFn = Hash; typename std::enable_if<std::is_unsigned<_Tp>::value, int>::type <anonymous> = 0]’:
rty.cpp:41:31: required from here
rty.cpp:24:5: error: static assertion failed: BAD signature
static_assert(is_functor<HashFn>(), "BAD signature");
^
rty.cpp:25:104: error: no type named ‘type’ in ‘class std::result_of<unsigned int (Hash::*(Hash, const char*, long unsigned int))(char*, long unsigned int) const>’
typedef typename std::result_of<decltype(&HashFn::operator())(HashFn, const char *, size_t)>::type return_type;
^
rty.cpp:26:75: error: no type named ‘type’ in ‘class std::result_of<unsigned int (Hash::*(Hash, const char*, long unsigned int))(char*, long unsigned int) const>’
static_assert(std::is_unsigned<return_type>::value, "BAD return type");
static_assert, :
static_assert(is_correct_functor<HashFn>(), "BAD implementation");
? .
++ 11 g++ 4.8