2011-12-25 2 views
2

Можно ли написать макрос, который может принимать в переменное число аргументов и расширяется так:отладки макросов для C++ с переменными аргументами без форматирования строки

quickdebug(a) -> cout << #a ": " << a; 
quickdebug(a,b) -> cout << #a ": " << a << #b ": "<< b; 

и т.д.

Если нет, возможно ли, по крайней мере, напечатать все аргументы, не передавая строки формата. например

quickdebug2(a) -> cout << a ; 
quickdebug2(a,b) -> cout << a << " " << b ; 

и т.д.

Например, в Java можно написать функцию, которая предоставляет мне подобную функциональность:

void debug(Object...args) 
{ 
    System.out.println(Arrays.deepToString(args)); 
} 
+0

Я думаю, что это возможно –

+0

В Java вы не можете делать '# a'. Таким образом, аналогия неверна. Вы можете выполнить то, что вы сделали на Java, с вариативными шаблонами в C++ (или несколькими невариантными шаблонами). – ybungalobill

+0

Что я сделал в Java, является аналогией для quickdebug2. И используя вариативные шаблоны, я не понимаю, как узнать размер и тип аргументов. Я хочу, чтобы я мог использовать его так же (что я могу сделать на Java): debug (42, «inner», 23.2) –

ответ

5

При использовании класса, который переопределяет, оператор:

class VariadicToOutputStream 
{ 
public: 
    VariadicToOutputStream(std::ostream& s, const std::string& separator = " ") : m_stream(s), m_hasEntries(false), m_separator(separator) {} 
    template<typename ObjectType> 
    VariadicToOutputStream& operator , (const ObjectType& v) 
    { 
     if (m_hasEntries) m_stream << m_separator; 
     m_stream << v; 
     m_hasEntries=true; 
     return *this; 
    } 
    ~VariadicToOutputStream() 
    { 
     m_stream << std::endl; 
    } 

private: 
    std::ostream& m_stream; 
    bool m_hasEntries; 
    std::string m_separator; 
}; 

Вы можете написать, например:

VariadicToOutputStream(std::cout) , 1, 0.5f, "a string"; 

Это может тогда быть обернуто макросом препроцессора:

#define VARIADIC_TO_STDOUT(...)  VariadicToOutputStream(std::cout),__VA_ARGS__; 

Таким образом, вы можете написать:

VARIADIC_TO_STDOUT(1, 0.5f, "a string"); 

Было бы легко добавить F.I. разделительные строки, которые должны использоваться между аргументами.

Редактировать: Я просто добавил пространство по умолчанию в качестве разделительной строки.

+0

Спасибо, Роберт, за волшебство. Это, наверное, самый классный C++-хак, который я когда-либо видел. Град! :) –

+0

@Nikhil: Спасибо, рад, что я смог помочь :) – Robert

+0

Я сделал небольшое изменение: я создал деструктор для этого класса, который печатает новую строку. Таким образом, каждый макросовый вызов, когда возвращается, печатает новую строку в конце. Если вы этого хотите, вы можете отредактировать его и в своем ответе =) –

1

Это можно сделать макрос, который VARIADIC таким образом принимает переменное количество аргументов. Синтаксис аналогичен функции:

#define quickdebug(...) functiontocall("test", __VA_ARGS__) 

Любой аргумент в списке после последнего имени аргумента в списке аргументов будут перечислены в __VA_ARGS__ включая любой разделяющей запятой.

Итак: quickdebug(1, 2, "123", 4.5) становится functioncall("test", 1, 2 , "123", 4.5)

Однако в каком-то момент вы должны использовать эти аргументы, и здесь он может стать чрезвычайно трудно, если вы не имеешь строку формата, или что-то еще, указывающий тип аргументов ,

Проблема в том, что при чтении переменных из списка переменных аргументов вам необходимо знать тип аргумента или, по крайней мере, его размер. Если бы я был вами, я бы выбрал другой подход.

Вы можете прочитать больше о вариативный макрос здесь: http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html

Смежные вопросы