簡體   English   中英

C++ std::enable_if 回退?

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

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