[英]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.