這個問題類似于在宏(C )中獲取函式的回傳型別,但它已經有 10 年歷史了,沒有人回答。任何其他解決方案都將被接受。
我想創建一個斷言宏,如果不滿足條件,它只會從函式回傳,例如:
#define ASSERT(X) if(!(X)) return {};
如果包含函式回傳 void,這不起作用,但我不想創建 2 個宏。我希望能夠在不更改代碼的情況下添加/洗掉回傳值。我的想法是創建一個輔助函式:
template<class T>
T re(){
if constexpr( std::is_same<T, void>::value ){
return;
}
else if constexpr( ! std::is_same<T, void>::value ){
return {};
}
}
現在宏可以像這樣作業:
double f(int *i){
if(i == nullptr){
typedef std::invoke_result<decltype(&f),int>::type T; // only works for this function
return re<T>();
}
return 1.0;
}
但是我需要當前函式的回傳型別 T 而不必呼叫類似的東西,ASSERT(i != nullptr, double)因為這樣我就可以簡單地使用 2 個宏。此外,像 __func__ 和 std::source_location 這樣的宏只是字串。
uj5u.com熱心網友回復:
這可以使用__PRETTY_FUNCTION__(GCC, Clang) / __FUNCSIG__(MSVC) 實作,這是一種非標準擴展,可為您提供當前函式的名稱,包括回傳型別。
您可以在編譯時分析字串以查看它是否包含void在其中:
#include <string_view>
struct AnyType
{
template <typename T>
operator T()
{
return {};
}
};
template <bool IsVoid>
auto foo()
{
if constexpr (IsVoid)
return;
else
return AnyType{};
}
#ifndef _MSC_VER
#define FUNCNAME __PRETTY_FUNCTION__
#else
#define FUNCNAME __FUNCSIG__
#endif
#define ASSERT(x) if (!bool(x)) return foo<std::string_view(FUNCNAME).starts_with("void ")>()
void x()
{
ASSERT(0);
}
int y()
{
ASSERT(0);
}
這需要更多的測驗,以確保您不能使用尾隨回傳型別以及向函式定義(屬性、呼叫約定等)添加各種內容來破壞它。
uj5u.com熱心網友回復:
如果你不知道該函式的回傳型別,也沒有表達X在宣告return X;的有效期為既是void-returning功能和函式回傳一個任意型別。
可以創建一個特殊的用戶定義的模板型別,它對各種型別return X;都有效。例如對于return std::nullopt;回傳 any 的函式總是有效的optional<T>。您可以從像 的物件創建具有類似隱式轉換屬性的類似型別,該型別具有nullopt允許void“攜帶”型別的特化(這std::optional<void>是不允許的,但您可以使用無狀態型別作為 的等價物void)。
當然,這現在需要呼叫者從您的型別中提取回傳值(如果有)。這也意味著它必須檢查是否回傳了值。
該expected<T, E>型別(其中有幾個實作)代表了一種像你在說什么。不同之處在于它們攜帶 a Tor E(帶有T==的特殊情況void),其中攜帶 anE表示回傳的使用者期望處理的錯誤值。
但所有這些都需要更改函式的實際回傳值。如果您一味地使用簡單型別,如void, double,int等,那么您將不得不為正在執行的任何回傳使用不同的宏。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/402518.html
標籤:
