Как сделать переменный макрос для std:: cout?
Как сделать макрос, который принял переменное количество аргументов, и распечатывает его с помощью std:: cout? Извините, если это вопрос noob, не удалось найти ничего, что разъяснило переменные макросы после поиска ответа.
Концептуальный пример:
#include <iostream>
#define LOG(...) std::cout << ... << ... << std::endl
int main() {
LOG("example","output","filler","text");
return 0;
}
выводит:
exampleoutputfillertext
Ответы
Ответ 1
Для этого вам не нужны макросы препроцессора. Вы можете написать это в обычном
С++. В С++ 11/14:
#include <iostream>
#include <utility>
void log(){}
template<typename First, typename ...Rest>
void log(First && first, Rest && ...rest)
{
std::cout << std::forward<First>(first);
log(std::forward<Rest>(rest)...);
}
int main()
{
log("Hello", "brave","new","world!\n");
log("1", 2,std::string("3"),4.0,'\n');
}
Живая демонстрация
В С++ 17:
template<typename ...Args>
void log(Args && ...args)
{
(std::cout << ... << args);
}
- это все, что требуется. Живая демонстрация
Вывод:
Hellobravenewworld!
1234
Исследование вариативные шаблоны,
пакеты параметров
и свернуть выражения
а не переменные макросы, которые редко бывают полезны в современном С++.
Ответ 2
При использовании Variadic макросов вам нужно __VA_ARGS__
, чтобы развернуть все аргументы.
Однако проблема состоит в том, что эти аргументы разделены запятой. Предположительно это просто разделяет аргументы на вызов функции, но поскольку макросы работают только с текстом, вы действительно можете использовать __VA_ARGS__
в других контекстах, где список разделенных запятой имеет смысл.
Трюк, который вы можете использовать, - это определить свой собственный оператор запятой для std::ostream
(тип std::cout
). Например:
#include<iostream>
#define LOG(...) std::cout , __VA_ARGS__ , std::endl
template <typename T>
std::ostream& operator,(std::ostream& out, const T& t) {
out << t;
return out;
}
//overloaded version to handle all those special std::endl and others...
std::ostream& operator,(std::ostream& out, std::ostream&(*f)(std::ostream&)) {
out << f;
return out;
}
int main() {
LOG("example","output","filler","text");
return 0;
}
Теперь вызов LOG будет расширяться до:
std::cout , "example" , "output" , "filler" , "text" , std::endl;
и запятые вызовут перегруженные операторы запятой.
Если вам не нравится перегружать operator,
загрязнение всех std::ostream
-s, вы можете инкапсулировать std::cout
своим собственным специальным классом журнала.
Ответ 3
Не уверен, что есть какой-либо способ определения вариационного макроса в С++ (по крайней мере, не переносимый). Почему вы не используете альтернативный шаблонный подход? Что-то вроде
#include <iostream>
void LOG() {}
template<typename Head, typename... Args>
void LOG(const Head& head, const Args&... args )
{
std::cout << head << " ";
LOG(args...);
}
int main()
{
LOG("This", "is" , "the", 3, "rd test");
}