2014-01-15 2 views
1

Мне известно, что для создания функции, принимающей входной поток, можно использовать макросы препроцессора. Для того, чтобы выяснить, что я имею в виду под «потоковый как» вход, позвольте мне дать вам пример (вход в LOGGER является «поток типа»):Использование «Stream-like» Input для функции C++

#include <iostream> 
#include <sstream> 

#define LOGGER(streamText) { \ 
    std::ostringstream buffer; \ 
    buffer << streamText;  \ 
    /* Some processing */  \ 
    std::cout << buffer.str() << std::endl; \ 
} 

int main(){ 
    LOGGER("Foo: " << "Bar!: " << 42); 
} 

Этот выход:

Foo: Bar !: 42

Я хотел бы иметь такой же интерфейс для обычной функции C++. Вроде как это (не компилировать код не действует C++):

// has: 
// - insert(std::ostringstream & str) function for obtaining content of a std::ostringstream 
// - formatting functions 
// - print(std::ostream & str) function 
class logger_class; 

logger_class logger_function(some_magic_type varName){ 
    std::ostringstream & str = varName; 
    logger_class log; 
    log.insert(str); 
    return log; 
} 

int main(){ 
    logger_class log = logger_function("Foo: " << "Bar!: " << 42); 
    log.format(some_formatting_options); 
    log.print(std::cout); 
} 

, который позволил бы формат вывода до фактического отправки его станд :: соиЬ.

Редактировать: C + + 11 и надменные решения также допускаются.

+0

Вы ищете перегруженные версии << - (? Замена станд :: вне или станд :: заблуждаться по имени регистратор) оператора – urzeit

+0

@urzeit Sort-оф. Я хочу, чтобы регистратор мог предположить, что введенный им вход был полным сообщением. Позвольте мне привести пример: один вариант форматирования - это раскраска, которая (при условии, что терминал ANSI) состоит из включения содержимого двумя разделителями. С помощью макро-решения это можно сделать легко, добавив разделители до и после потоковой передачи сообщения журнала в выходной поток (поскольку все сообщение журнала содержится в аргументе макроса). – elemakil

+0

Я хочу, чтобы функция возвращала объект журнала, потому что это позволяет установить параметры форматирования с помощью цепочки методов, то есть: 'logger_function (« Foo »<< 42) .log_level (500) .color (RED) .weight (BOLD) .end_line(); ' – elemakil

ответ

2

Использование C++ 11, вы можете использовать шаблоны VARIADIC:

template <typename T> 
std::ostringstream & fill_stream(std::ostringstream & str, T&& t) 
{ 
    return (str << std::forward<T>(t)); 
} 

template <typename T, typename... Vs> 
std::ostringstream & fill_stream(std::ostringstream & str, T&& t, Vs&&... vs) 
{ 
    str << std::forward<T>(t); 
    return fill_stream(std::forward<Vs>(vs)...); 
} 

template <typename... Ts> 
logger_class logger_function(Ts&&... vars){ 
    std::ostringstream & str; 

    if (!fill_stream(str, std::forward<Ts>(vars)...)) 
    { 
     //Error! 
    } 

    logger_class log; 
    log.insert(str); 
    return log; 
} 

Тогда:

int main() 
{ 
    logger_class log = logger_function("Foo: ", "Bar!: ", 42); 
    log.format(some_formatting_options); 
    log.print(std::cout); 
} 

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

template <typename... Ts> 
logger_class<Ts&&...> logger_function(Ts&&... vars){ 
    // logger_class should probably store its arguments as a tuple 
    logger_class<Ts&&...> log (std::forward<Ts>(vars)...); 
    return log; 
} 

int main() 
{ 
    auto log = logger_function("Foo: ", "Bar!: ", 42); 
    log.format(some_formatting_options); 
    log.print(std::cout); 
} 
Смежные вопросы