簡體   English   中英

可變宏:無法通過“...”傳遞非平凡可復制類型的對象

[英]Variadic Macro: cannot pass objects of non-trivially-copyable type through '…'

我正在嘗試為日志記錄機制編寫一個宏。 我寫了一個可變參數宏,但它不適用於std::string 代碼如下所示:

#include <stdio.h>
#include <string>


#define LOG_NOTE(m, ...) printf(m, ##__VA_ARGS__)

int main()
{
    std::string foo = "random string";
    int bar = 5;
    LOG_NOTE("%s %d %s", "Hello World", bar, foo);

    return 0;
}

如果我像下面這樣調用宏,我不會得到任何錯誤。

LOG_NOTE("%s %d %s", "Hello World", bar, "random string");

編譯器輸出:

在函數“int main()”中:5:49:錯誤:無法通過“...”11:5 傳遞非平凡可復制類型“std::string {aka class std::basic_string}”的對象:注意: 在宏 'LOG_NOTE' 的擴展中

這里的問題不是可變參數宏,而是對printf的調用。 查看文檔:格式說明符"%s"對應於char* ,而不是std::string printf只能處理原始內置類型。 您可以將調用更改為

LOG_NOTE("%s %d %s", "Hello World", bar, foo.c_str());

來解決這個問題。

我寫了一個可變參數宏

別。 使用可變參數模板函數。

您遇到的實際問題是您試圖通過 C API ( printf ) 傳遞 C++ 對象 ( std::string )。 這不可能。

您需要一些轉換機制,例如:

#include <stdio.h>
#include <string>

template<class T>
decltype(auto) convert_for_log_note(T const& x)
{
    return x;
}

decltype(auto) convert_for_log_note(std::string const& x)
{
    return x.c_str();
}


template<class...Args> 
void LOG_NOTE(const char* format, Args&&...args)
{
    printf(format, convert_for_log_note(args)...);
}

int main()
{
    std::string foo = "random string";
    int bar = 5;
    LOG_NOTE("%s %d %s\n", "Hello World", bar, foo);

    return 0;
}

示例輸出:

Hello World 5 random string

http://coliru.stacked-crooked.com/a/beb3431114833860

更新:

對於 C++11,您需要手動拼出返回類型:

#include <stdio.h>
#include <string>

template<class T>
T const& convert_for_log_note(T const& x)
{
    return x;
}

const char* convert_for_log_note(std::string const& x)
{
    return x.c_str();
}


template<class...Args> 
void LOG_NOTE(const char* format, Args&&...args)
{
    printf(format, convert_for_log_note(args)...);
}

int main()
{
    std::string foo = "random string";
    int bar = 5;
    LOG_NOTE("%s %d %s\n", "Hello World", bar, foo);

    return 0;
}

您不能將對象傳遞給printf ,因此您目前必須使用

LOG_NOTE("%s %d %s", "Hello World", bar, foo.c_str());

如果您不需要格式化,只需將每個參數用空格分隔開,您可以簡單地使用可變參數模板而不是 MACRO:

template <typename ... Ts>
void LOG_NOTE(const Ts&...args)
{
    const char* sep = "";
    (((std::cout << sep << args), sep = " "), ...); // C++17 folding expression
    // C++11/C++14 version are more verbose:
    // int dummy[] = {0, ((std::cout << sep << args), (sep = " "), 0)...};
    // static_cast<void>(dummy); // avoid warning for unused variable
}

int main()
{
    std::string foo = "random string";
    int bar = 5;
    LOG_NOTE("Hello World", bar, foo);
}

演示

我無法在我嘗試過的任何 C++11 編譯器中獲得 @richardhodges 好的解決方案。 但是,以下適用於gcc -std=c++11

#include <stdio.h>
#include <string>

template<class T>
T convert_for_log_note(T const& x)
{
    return x;
}

inline const char* convert_for_log_note(std::string const& x)
{
    return x.c_str();
}


template<class...Args> 
void LOG_NOTE(const char* format, Args&&...args)
{
    printf(format, convert_for_log_note(args)...);
}

int main()
{
    std::string foo = "random string";
    int bar = 5;
    LOG_NOTE("%s %d %s\n", "Hello World", bar, foo);

    return 0;
}

inline關鍵字對於 Arduino C++ 編譯器的上述解決方案是必需的,而其他 g++ 編譯器不需要它(無論如何我都嘗試過)。 如果沒有這個關鍵字,Arduino 代碼會編譯,但鏈接器會抱怨多個定義。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM