2

まず第一に、これは機能しますが、非常にバグがあります。intsfloatsdoubles、 、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*何か他のことを試してみてください?

より高度な varidic 関数を探しましたが、それらはすべて引数の数の pramiter を必要とするようです。または 1 つのタイプのみを許可します。また、連続ループが必要な場合は、プログラムの別の場所にループを設定します。(これで全部だと思います)

4

3 に答える 3

3

C++11 がオプションである場合 (<thread>ヘッダーが含まれていることを考慮すると、これが当てはまるようです)、C スタイルの variadic functions の代わりにvariadic テンプレートを使用できます。

このようなものでうまくいくはずです(今はテストできないので、うまくいかない場合は教えてください。修正を試みます):

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 の機能です。私の知る限り、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_ordernullary ラムダの変数セットを取り、それらを順番に実行します。

次に、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ます。そこでは、各引数を一度に 1 つずつ詰め込むための一連のタスクをパッケージ化しstringstreamます。

個人的には、スレッドを立ち上げてすぐにスレッドに参加することは、インラインで実行する場合と比べてあまり改善されないため、この設計は使用しません。

于 2013-03-29T20:47:45.570 に答える