问题
I need to check, if a containers erase function returns the iterator. I'd normally check for the function signature via e.g. boost. But in case of a boost class (e.g. flat_set) erase is inherited and thus not found by the check. But I really need it. SFINAE to check for inherited member functions only shows a C++11 solution which I can't use yet.
I tried something like this:
template <typename T>
class has_member_func_erase_it_constit
{
typedef typename T::iterator iterator;
typedef typename T::const_iterator const_iterator;
typedef BOOST_TYPEOF_TPL(&T::erase) eraseType;
typedef typename boost::function_types::result_type<eraseType>::type result;
public:
static const bool value = boost::is_same<iterator, result>::value;
};
template<class T>
struct EraseReturnsIterator
{
static CONSTEXPR bool value = has_member_func_erase_it_constit<T>::value;
};
But it fails since erase is overloaded. I'd probably need decltype or something like that to check the return type from a compile-time invocation of erase with const_iterator, but I can't find one.
How is this possible in pre C++11?
This does also not work if there is an erase function returning void:
template <typename T>
class has_member_func_erase_it
{
typedef typename T::iterator iterator;
typedef typename T::const_iterator const_iterator;
typedef char yes[1];
typedef char no [2];
static T makeT();
static iterator makeIt();
typedef BOOST_TYPEOF_TPL(makeT().erase(makeIt())) result;
public:
static const bool value = boost::is_same<iterator, result>::value;
};
回答1:
The following works:
/// "Stores a type"
template<typename T> struct Type2Type{
typedef T type;
};
/// Evil hackery to put an expression into a type
template<typename T>
Type2Type<T> operator,(T, Type2Type<void>);
template<typename T>
T declval();
template<class T>
struct EraseReturnsIterator
{
typedef typename T::iterator iterator;
typedef BOOST_TYPEOF_TPL((declval<T>().erase(declval<iterator>()), Type2Type<void>())) result;
static CONSTEXPR bool value = boost::is_same<iterator, typename result::type>::value;
};
Basicly we just call the function whose return type we need. If no function of this type ever returned void than BOOST_TYPEOF_TPL would already work. Unfortunately erase CAN return void which breaks the implementation as it tries to pass "void&" somewhere down the stack.
So to avoid the void (no pun intended) we put it in a type, that holds a type. To be able to do this for expressions, we overload the comma operator. This way result equals "Type2Type" which we can easily read. Done!
Idea for the comma-overload: https://stackoverflow.com/a/5553460/1930508
来源:https://stackoverflow.com/questions/31843393/check-for-function-signature-also-for-inherited-functions