I want to have a compile-time check in my code which ensures that a given class overloads the () operator, that this operator takes a const char * and a size_t as parameters and that its return type is an unsigned integer.
I have tried several code snippets taken from StackOverflow, but I am not satisfied with the solution I have written:
#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;
} // detail::
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 is what I don't like about my code:
-
If I substitute
inttosize_tin the parameter list when overloading the()operator, there is no error at compilation, becausesize_tcan be implicitly cast toint. -
If the signature is incorrect (e.g. I remove the
constwhen overloading the operator), the first assert fails. However, because compilation does not stop, I get three error messages, and the compiler output is somewhat clutteredrty.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"); -
I'd like to have a single call to static_assert, something like:
static_assert(is_correct_functor<HashFn>(), "BAD implementation");
How can I achieve this? Thanks for your help.
I am using C++11 and compiling with g++4.8
Aucun commentaire:
Enregistrer un commentaire