2013-03-29 1 views
2

Хорошо, прежде всего до сих пор это работает, но чрезвычайно багги. Я хочу, чтобы он мог принимать ints, floats, doubles, strings и char*s. Это вроде работы, пытаясь все как char *, но если это не удается, мне бы хотелось, чтобы он повторил это как другой тип. Мне также хотелось бы, чтобы мне не пришлось передавать количество параметров. (Больше на дне)Вариадическая функция с различными типами, переходящая к резьбовому cout

#include <iostream> 
#include <cstdlib> 
#include <sstream> 
#include <iostream> 
#include <windows.h> 
#include <ctime> 
#include <tchar.h> 
#include <stdio.h> 
#include <vector> 
#include <thread> 
const enum loglevel{INFO,WARNING,OK,SEVERE}; 
void logHelperMessage(loglevel,int, ...); 
void threadedloghelpermessage(loglevel,string); 

int main(int argc, char **argv) 
{ 
    logHelperMessage(INFO,4,"Hi","I","DO","WORK"); 
} 

void logHelperMessage(loglevel severity,int number, ...) 
{ 
    va_list messages; 
    va_start(messages,number); 
    std::stringstream ss; 

    for(int i = 0;i < number;i++) 
    { 
      ss << va_arg(messages,char*); 
    } 
    std::string s = ss.str(); 
    thread t1(threadedloghelpermessage,severity,s); 
    t1.join(); 
} 

void threadedloghelpermessage(loglevel severity,string message) 
{ 
    //TODO: implement a stack? 
    switch (severity) 
    { 
    case INFO: 
     SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_BLUE); 
     cout << "[IF]"; 
     break; 
    case WARNING: 
     SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x06); 
     cout << "[WA]"; 
     break; 
    case OK: 
     SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_GREEN); 
     cout << "[OK]"; 
     break; 
    case SEVERE: 
     SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED); 
     cout << "[ER]"; 
     break; 
    default: 
     break; 
    } 
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x08); 
    time_t t = time(0); 
    struct tm now; 
    localtime_s(&now, &t); 
    cout << "["; 
    int hour = now.tm_hour; 
    if(hour < 10) 
    { 
     cout << 0 << hour << ":"; 
    } 
    else 
    { 
     cout << hour << ":"; 
    } 
    int minu = now.tm_min; 
    if(minu < 10) 
    { 
     cout << 0 << minu << ":"; 
    } 
    else 
    { 
     cout << minu << ":"; 
    } 
    int sec = now.tm_sec; 
    if(sec < 10) 
    { 
     cout << 0 << sec; 
    } 
    else 
    { 
     cout << sec; 
    } 
    cout << "] "; 
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x07); 
    cout << message << endl; 
} 

Теперь, есть в любом случае:

  1. Есть выход нитей к консоли без них сбой или подвесить основную программу как нить воссоединяется
  2. (ThreadPool?)
  3. Использование: logHelperMessage(logLevel,firstpram,...) (используйте первый флажок, чтобы получить свое пометку и перейти оттуда?)
  4. В: ss << va_arg(messages,char*); если он не работает как char*, попробуйте что-нибудь еще?

Я огляделся по более продвинутым варидическим функциям, но, похоже, для них требуется целый ряд аргументов. или только один тип. Кроме того, если требуется непрерывный цикл, у меня есть петля, установленная где-то еще в программе. (я думаю, что это все)

ответ

3

Если C++ 11 является для вас вариантом (и учитывая включение заголовка <thread>, это, по-видимому, так), вы могли бы use variadic templates instead of C-style variadic functions.

Что-то, как это должно сделать работу (не могу проверить это прямо сейчас, поэтому, пожалуйста, скажите мне, если он не работает, и я постараюсь это исправить):

template<typename T> 
void insert_messages(std::stringstream& ss, T&& arg) 
{ 
    ss << std::forward<T>(arg); 
} 

template<typename T, typename... Ts> 
void insert_messages(std::stringstream& ss, T&& arg, Ts&&... args) 
{ 
    ss << std::forward<T>(arg); 
    logMessage(std::forward<Ts>(args)...); 
} 

template<typename... Ts> 
void logHelperMessage(loglevel severity, Ts&&... args) 
{ 
    std::stringstream ss; 
    insert_messages(ss, std::forward<Ts>(args)...); 

    std::string s = ss.str(); 
    std::thread t1(threadedloghelpermessage,severity,s); 
    t1.join(); 
} 
+0

делает это только для ввода одного типа коляски? IE: все строки или все ints. –

+0

@StevenVenham: Вы имеете в виду, что он должен проверить, что все аргументы одного типа? –

+0

Нет, я имею в виду, начиная с его типа T, как он принимает аргументы и использует их, как там T? Например, если я передал: «Привет», 1,3.4, «O» понял бы, что существует множество различных типов аргументов? –

1

Однако функции Variadic могут принимать разные типы переменных. Сама функция должна точно знать, какой тип каждого аргумента. Посмотрите, например, на printf(). Вы можете передавать строки, целые числа, точки и т. Д., А строка формата сообщает функции точно, какой тип каждой переменной.

Что касается количества аргументов, это особенность C99. AFAIK Visual Studio компилятор не поддерживает его.

Вы можете найти пример для C99 в этом question.

+0

ОК, поэтому из-за меня с помощью vs2012 им не удалось это сделать? –

0

В C + +11, это легко:

во-первых, некоторые вспомогательные функции:

void do_in_order() {}; 
template<typename Lambda0, typename... Lambdas> 
void do_in_order(Lambda0&& L0, Lambdas&&... Ls) { 
    std::forward<Lambda0>(L0)(); 
    do_in_order(std::forward<Lambdas>(Ls)...); 
} 

do_in_order занимает variardic набор нульарными лямбды, и запускает их в порядке.

Далее logHelperMessage:

template<typename... Args> 
void logHelperMessage(loglevel severity,Args&&... args) { 
    std::stringstream ss; 

    do_in_order([&](){ 
    ss << std::forward<Args>(args); 
    }...); 
    std::string s = ss.str(); 
    thread t1(threadedloghelpermessage,severity,s); 
    t1.join(); 
} 

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

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

+0

'template void execute_all (F && ... f) {используя T = char []; T {'\ 0', (std: forward (f)(), void(), '\ 0') ...}; } ' –

+0

@Yakk Iv добавлен в некоторый код после публикации этого сообщения, в котором используется bool, чтобы показать, закончен ли поток, и я использую вектор информации для хранения сообщений. поэтому .join находится внутри оператора if. –

+0

@LucDanton Да? Это тоже сработает. Более неясным в том, как это работает, и о количестве персонажей. :) – Yakk