2014-10-09 7 views
0

Я хотел бы написать обобщенную функцию в C++Generic функции, чтобы получить отладочную строку для всех типов и коллекций в C++

template<class T> 
string GetDebugString(const T& t); 

который может универсально получает отладочную строку для всех типов. Моя проблема заключается в том, как использовать черты для различения между различными типами:

1) Примитивные типы и строки: получают прямое представление строки.

2) Тип и тип класса: вызывают его метод «string DebugString()». Я бы применил этот метод для всех классов. Метод мог бы вызвать рекурсивно вызов GetDebugString.

3) Указатели и умные указатели: разыменования них и последующие 1) или 2)

4) Коллекция, такие как вектор, набор или карт: перебрать весь его элемент, получить отладочную строку для каждого элемента следующие 1), 2) и 3) и собрать их в некоторых форматах.

Как мы можем это сделать с помощью std :: enable_if?

+0

Вы можете использовать SFINAE, чтобы проверить, обрабатываете ли вы тип методом «DebugString» и перегружаете практически все остальное, о чем вы упомянули. Никаких признаков не требуется. Если вы выполните поиск на этих условиях, вы сможете копировать/скрестить что-то и просить о помощи по конкретным вопросам. –

+0

Я могу использовать C++ 11. – yuefengz

+0

Это могло бы помочь вам: http://stackoverflow.com/questions/4850473/pretty-print-c-stl-containers – Chnossos

ответ

1

Один из способов - использовать специализацию для записи конкретных типов реализации. Например:

template<> 
string GetDebugString(int& t) 
{ 
    return "It's an int"; 
} 

template<> 
string GetDebugString(string& t) 
{ 
    return t; 
} 

template <class T> 
string GetDebugString(T& t) 
{ 
    //Now that you've taken care of the special cases 
    //write a function to handle the generic 

} 
1

Примерно так:

#include <iostream> 

#define AUTO_RETURN(...) -> decltype(__VA_ARGS__) {return (__VA_ARGS__);} 

std::string GetDebugString(char ch) {return {ch};} 
std::string GetDebugString(char const* str) {return str;} 
std::string GetDebugString(std::string const& str) {return str;} 

template <typename T> 
auto GetDebugString(T t) AUTO_RETURN(std::to_string(t)) 

// No AUTO_RETURN here because of GCC 
template <typename T> 
auto GetDebugString(T ptr) -> decltype(GetDebugString(*ptr)) 
{ 
    return "Pointer to " + GetDebugString(*ptr); 
} 

template <typename T> 
auto GetDebugString(T&& t) AUTO_RETURN(std::forward<T>(t).DebugString()) 

template <typename T, typename U> 
auto GetDebugString(std::pair<T, U> const& p) AUTO_RETURN('<' + GetDebugString(p.first) + ',' + GetDebugString(p.second) + '>') 

template <typename Range> 
auto GetDebugString(Range&& c) -> decltype(std::begin(c), std::end(c), std::string()) 
{ 
    // Size obtainment can be optimized for containers with size member-functions 
    std::string str = "Range with " + std::to_string(std::distance(std::begin(c), std::end(c))) + " elements: \n\t"; 
    for (auto const& elem : c) 
     str += GetDebugString(elem) + ", "; 
    return str; 
} 

int main() 
{ 
    int i = 23; 
    auto ptr = &i; 
    char const str[] = "Hallo!"; 
    auto list = {4, 5, 5, 6, 8}; 

    std::cout << GetDebugString(i) << '\n'; 
    std::cout << GetDebugString(ptr) << '\n'; 
    std::cout << GetDebugString(str) << '\n'; 
    std::cout << GetDebugString(list) << '\n'; 
} 

Demo. Обратите внимание, что вам может потребоваться ввести рейтинги, чтобы избежать двусмысленности; например, когда тип имеет как метод DebugString, так и begin/end функции-члены. Я просто не использовал диапазон ADL для доступа.

+0

Можете ли вы также рассказать мне, как иметь дело с картой? – yuefengz

+0

@Fake Добавлена ​​перегрузка для 'pair'. – Columbo

+0

Спасибо. Так возможно ли иметь отдельную GetDebugString для карты? – yuefengz