Variadic-функция с разными типами, переходящая к резьбовому методу

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

#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. Пусть потоки выводятся на консоль без сбоев или зависания основной программы при возобновлении потока (threadpool?)
  2. Использование: logHelperMessage(logLevel,firstpram,...) (использовать первый параметр, чтобы получить свою позицию mem и перейти оттуда?)
  3. В: ss << va_arg(messages,char*); если он не работает как char* возможно попробовать что-то еще?

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

2

Решение

Если C ++ 11 является вариантом для вас (и с учетом включения <thread> кажется, это так), вы могли бы использование вариационные шаблоны вместо вариационных функций в стиле C.

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

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();
}
3

Другие решения

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

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

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

1

В 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 берет вариационный набор нулевых лямбд и запускает их по порядку.

Следующий, 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
По вопросам рекламы [email protected]