Как проверить, определил ли класс определение вложенного класса или typedef в C ++ 11? - PullRequest
7 голосов
/ 10 марта 2012

В моем проекте я хочу реализовать шаблонный прокси-класс некоторых существующих больших классов. Существующие классы являются библиотечными классами, поэтому их нельзя изменить. В большинстве случаев клиенты не знают, что объекты являются экземплярами прокси-класса или более крупного класса. Однако в некоторых случаях клиенты ДОЛЖНЫ знать подробную информацию о классе. Поскольку прокси-класс сам по себе является шаблоном, я не думаю, что простая перегрузка функций по имени класса может решить эту проблему. Возможно, я решил, что можно добавить внутренний вложенный класс или typedef внутри прокси-класса, и клиент проверит, существует ли этот class / typedef для получения информации о классе. Мой вопрос: как проверить, определил ли класс определение вложенного класса или typedef в C ++ 11?

Следующие коды показывают пример:

#include <iostream>
#include <functional>
#include <string>
#include <vector>
#include <type_traits>

typedef std::string CBig1;  //  use string for demonstration
typedef std::string CBig2;  //  use string for demonstration

//class CBig1;   // the bigger class 1, codes of which can not be changed
//class CBig2;   // the bigger class 2, codes of which can not be changed

template <typename _Big, typename _Other>
class CProxy
{
public:
    struct proxy_tag { };
};

//  how to implement this ?
//  the proxy traits class, if defined _T::proxy_tag, the ``type'' will be std::true_type, otherwise the ``type'' will be std::false_type
template <typename _T>
struct is_proxy
{
    //typedef std::true_type type;
    //typedef std::false_type type;
};

template <typename _T>
void ClientHelp(const _T& t, std::false_type)
{
    //  process real class
    std::cerr << "real class" << std::endl;
}

template <typename _T>
void ClientHelp(const _T& t, std::true_type)
{
    //  process proxy class
    std::cerr << "proxy class" << std::endl;
}

template <typename _T>
void Client(const _T& t)
{
    ClientHelp(t, typename is_proxy<_T>::type());
}

int main(int argc, char* argv[])
{
    CBig1 b;
    CProxy<CBig1, int> p;
    Client(b);
    Client(p);
    return 0;
}

Как реализовать класс черт is_proxy?

Ответы [ 2 ]

18 голосов
/ 10 марта 2012

Вы можете использовать облегченную классификацию типов

template<class T, class R = void>  
struct enable_if_type { typedef R type; };

template<class T, class Enable = void>
struct test : std::false_type {};

template<class T>
struct test<T, typename enable_if_type<typename T::is_proxy_tag>::type> : std::true_type
{};

template <typename _Big, typename _Other>
class CProxy
{
  public:
  typedef void is_proxy_tag;
};

Итак, чтобы сделать класс прокси, просто добавьте это

typedef void is_proxy_tag;

и СФИНА в enable_if_type выберет правильную true_type / false_type специализацию

Обратите внимание, что использование boost::mpl::true_ вместо std::true_type и т. Д. Позволяет использовать это решение для C ++ 03.

11 голосов
/ 10 марта 2012

В дополнение к версии C ++ 03, в C ++ 11 вы получите decltype:

template <typename T>
auto is_proxy(T const&) -> decltype(T::proxy_tag{}, std::true_type{}) {
  return std::true_type{};
}

std::false_type is_proxy(...) { return std::false_type{}; }

И ваша реализация Client становится:

template <typename T>
void Client(T const& t) {
  ClientHelp(t, is_proxy(t));
}

Сладкий, не правда ли?

...