Из того, что я понимаю, вы хотите сделать общий тест, чтобы увидеть, имеет ли класс определенную функцию-член. Это может быть выполнено в 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; };
В обоих случаях сигнатура метода test<U>(int)
видна только в том случае, если U
имеет метод size
, так как в противном случае оценка либо decltype
, либо sizeof
(в зависимости от используемой версии) завершится неудачно. , который затем удалит метод из рассмотрения (из-за SFINAE
. Длинные выражения std::declval<U>().size(), void(), std::true_type()
являются злоупотреблением оператором запятой C ++, который будет возвращать последнее выражение из списка, разделенного запятыми, поэтому это гарантирует, что тип известный как std::true_type
для варианта C ++ 11 (а sizeof
оценивает int
для варианта C ++ 03). void()
в середине только там, чтобы убедиться, что нет никаких странных перегрузок оператор запятой, мешающий оценке.
Конечно, это вернет true, если T
имеет метод size
, который можно вызывать без аргументов, но не дает никаких гарантий относительно возвращаемого значения. Я предполагаю, что вы, вероятно, захотите обнаружить только те методы, которые не возвращают void. Это может быть легко достигнуто с небольшой модификацией метода test(int)
:
// C++11
template <typename U>
static typename std::enable_if<!is_void<decltype(std::declval<U>().size())>::value, std::true_type>::type test(int);
//C++03
template <typename U>
static typename std::enable_if<boost::enable_if_c<sizeof(static_cast<U*>(0)->size()) != sizeof(void()), yes>::type test(int);