据我所知,您想要一个通用的测试来检查一个类是否具有特定的成员函数。在C++中,可以使用
SFINAE来实现这一点。在C++11中,由于可以使用
decltype
,所以这非常简单:
template <typename T>
struct has_size {
private:
template <typename U>
static decltype(std::declval<U>().size(), void(), std::true_type()) test(int);
template <typename>
static std::false_type test(...);
public:
typedef decltype(test<T>(0)) type;
enum { value = type::value };
};
如果您使用C++03,由于缺少
decltype
,所以需要滥用
sizeof
,这使得它有点困难:
template <typename T>
struct has_size {
private:
struct yes { int x; };
struct no {yes x[4]; };
template <typename U>
static typename boost::enable_if_c<sizeof(static_cast<U*>(0)->size(), void(), int()) == sizeof(int), yes>::type test(int);
template <typename>
static no test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(yes) };
};
当然,这里使用了
Boost.Enable_If
,这可能是一个不需要的(也不必要的)依赖。但是自己编写
enable_if
非常简单:
template<bool Cond, typename T> enable_if;
template<typename T> enable_if<true, T> { typedef T type; };
在这两种情况下,如果U没有一个size方法,那么只有当方法签名test
(int)可见时,依据SFINAE原则,将会从考虑中移除该方法。std::declval().size(), void(), std::true_type()是对C++逗号运算符的滥用,它将返回逗号分隔列表中的最后一个表达式,因此这可以确保类型在C++11版本中被知道为std::true_type(并且sizeof在C++03版本中评估为int)。中间的void()只是为了确保没有奇怪的逗号运算符重载干扰评估。
当然,如果 T
有一个可无需参数调用的 size
方法,则此方法将返回 true,但不能保证返回值。我假设您可能只想检测那些不返回 void 的方法。可以通过轻微修改 test(int)
方法来轻松实现此目标:
template <typename U>
static typename std::enable_if<!is_void<decltype(std::declval<U>().size())>::value, std::true_type>::type test(int);
template <typename U>
static typename std::enable_if<boost::enable_if_c<sizeof(static_cast<U*>(0)->size()) != sizeof(void()), yes>::type test(int);