2

好吧,首先到目前为止,这是可行的,但是非常有问题。我希望它能够接受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. 让线程输出到控制台,而不会在线程重新加入时使主程序崩溃或挂起(线程池?)
  2. 使用:(logHelperMessage(logLevel,firstpram,...)使用第一个参数获取其内存位置并从那里开始?)
  3. 在:ss << va_arg(messages,char*);如果它不能作为一个char*可能尝试别的东西?

我四处寻找更高级的可变函数,但似乎它们都需要参数数量的参数。或只允许一种类型。另外,如果需要连续循环,我会在程序的其他地方设置一个循环。(我认为这就是一切)

4

3 回答 3

3

如果 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();
}
于 2013-03-29T20:46:30.873 回答
1

然而,可变参数函数可以采用不同类型的变量。函数本身必须确切地知道每个参数是哪种类型。以 printf() 为例。您可以将字符串、整数、指针等传递给它,格式字符串会准确地告诉函数每个变量是什么类型。

关于参数的数量,这是 C99 的一个特性。AFAIK Visual Studio 编译器不支持它。

您可以在此问题中找到 C99 的示例。

于 2013-03-29T20:41:31.463 回答
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接受一组可变的 nullary lambda,并按顺序运行它们。

接下来,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,我们打包一堆任务,一次将每个 arg 塞入stringstream一个。

就个人而言,我不会使用这种设计,因为启动一个线程并立即加入它对内联并没有太大的改进。

于 2013-03-29T20:47:45.570 回答