[英]C++ std::enable_if fallback?
我正在設置可變參數模板 function 以便能夠在特定系列的類上調用各種 function 重載。 到目前為止,當不受支持的 class 傳遞給 function 時,我已經能夠“破壞”編譯,但我希望能夠提供有效的后備來處理運行時“不受支持”的情況。
當前的實現是這樣的:
struct ClassA {};
struct ClassB {};
struct ClassC {};
template<typename T> struct is_my_class : std::false_type {};
template<> struct is_my_class<ClassA> : std::true_type {};
template<> struct is_my_class<ClassB> : std::true_type {};
template<typename T>
constexpr bool is_my_class_v = is_my_class<T>::value;
void runOverload(ClassA c) { printf("ClassA overload\n"); }
void runOverload(ClassB c) { printf("ClassB overload\n"); }
template<typename T, typename = std::enable_if_t<is_my_class_v<T>>>
void run(T myClass)
{
runOverload(myClass);
};
template<typename T, typename... Ts>
void run(T myClass, Ts... classesLeft)
{
run(myClass);
run(classesLeft...);
};
int main()
{
ClassA a;
ClassB b;
ClassC c;
run(a, b); // works
run(c); // does not compile
}
在這里,我進行了兩次最有希望(但仍然失敗)的嘗試來回退run
:
1 - 添加一個簡單的!
在is_my_class<T>
前面,給我以下錯誤: error C2995: 'void run(T)': function template has already been defined
template<typename T, typename = std::enable_if_t<!is_my_class_v<T>>>
void run(T myClass)
{
printf("Not supported\n");
};
2 - 制作一個更“主要”的模板定義,這會產生一個可悲但明顯的: error C2668: 'run': ambiguous call to overloaded function
template<typename T>
void run(T myClass)
{
printf("Not supported\n");
};
編輯我忘了指定我正在尋找一個也與 C++11/14 兼容的解決方案
您可以完全避免enable_if
,而只需使用編譯時if
來決定要執行哪些代碼:
template<typename T>
void run(T myClass)
{
if constexpr (is_my_class_v<T>)
runOverload(myClass);
else
printf("Not supported\n");
}
這是一個演示。
即使如果 c++17 可用,我會推薦 @cigien 的解決方案,但我想補充一點,可以通過更改enable_if
模板參數的類型,從而在 ZF4A2D1DA1DA1DA520DF2FF7A41041E79B59Z 之前緩解歧義問題,從而更改“回退”的簽名功能”。 以下代碼應該可以正常工作:
template<typename T, std::enable_if_t<!is_my_class_v<T>, int> = 0>
//template<typename T>
void run(T myClass) {
printf("error\n");
};
CompilerExplorer上提供完整代碼,在 GCC 和 Clang 主干上進行了測試。
我還想補充一點,在我能想象的所有用例中,最好有一個編譯時錯誤(例如,您可以通過使用static assertion
而不是SFINAE
來實現)。
在這里,您可以了解為什么 function 聲明並不模棱兩可,即使使用兩個“整數”作為模板 arguments 也是如此。
我編寫了以下代碼並且它有效。 我認為您只是弄亂了 SFINAE 的語法。
#include <iostream>
#include <type_traits>
struct ClassA {};
struct ClassB {};
struct ClassC {};
template<typename T> struct is_my_class : std::false_type {};
template<> struct is_my_class<ClassA> : std::true_type {};
template<> struct is_my_class<ClassB> : std::true_type {};
template<typename T>
constexpr bool is_my_class_v = is_my_class<T>::value;
void runOverload(ClassA c) { printf("ClassA overload\n"); }
void runOverload(ClassB c) { printf("ClassB overload\n"); }
template<typename T, std::enable_if_t<is_my_class_v<T>,int> = 0>
void run(T myClass)
{
runOverload(myClass);
};
template<typename T, std::enable_if_t<not is_my_class_v<T>,int> = 0>
void run(T myClass)
{
printf("Not supported\n");
};
// wrote an extra SFINEA here to ensure that Ts aren't empty - else it might be an ODR issue despite the fact that it compiles
template<typename T, typename... Ts, std::enable_if_t<sizeof...(Ts) != 0,int> = 0>
void run(T myClass, Ts... classesLeft)
{
run(myClass);
run(classesLeft...);
};
int main()
{
ClassA a;
ClassB b;
ClassC c;
run(a, b);
run(c);
}
它打印
A類重載
B 類重載
不支持
有一個后備runOverload
模板
template<typename T>
void runOverload(T myClass)
{
printf("Not supported\n");
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.