事情是這樣的,有人問我他想做到這件事:
enum class Enum {A, B, C ... };
template <Enum E, int N>
struct MyStruct {
void func();
};
template <int N>
void MyStruct<Enum::A, N>::func() {...}
看完後我就說了,你想做的事 function 的偏特化,這在 C++ 是不被允許的,所以當然會編譯失敗囉
當然,下一個問題就是:那要怎麼做?
以下提供幾個方法 (先不考慮整個 class 重構把 template argument 拆掉)
1. compile-time if (需求:C++17)
enum class Enum {A, B, C ... };
template <Enum E, int N>
struct MyStruct {
void func() {
if constexpr (E == Enum::A) { ... }
else { ... }
}
};
這情況最簡單又最好寫的應該是 compile-time if,沒有太多複雜的 code,效能上也不會有額外負擔
2. std::enable_if (需求:C++11)
沒有 compile-time if 能用的話,基本上就是用 SFINAE,缺點就是會比較醜...
enum class Enum {A, B, C ... };
template <Enum E, int N>
struct MyStruct {
template <Enum U=E>
std::enable_if_t<U==Enum::A> func() { ... }
template <Enum U=E>
std::enable_if_t<U!=Enum::A> func() { ... }
};
利用 SFINAE,藉由判斷 E 的 value 是哪一種區分成兩種實作,最後只會有一個留下來。
要注意的是這邊的 template <Enum U=E> 是省不掉的,不然 C++ 會認為兩個都是 MyStruct 應該要有的 member function,不適用 SFINAE。
3. 全列
聽起來好像有點笨,但確實也是一種方式。當然僅適用可以全列的情況
enum class Enum {A, B, C ... };
template <Enum E, int N>
struct MyStruct {
void func();
};
template <>
void MyStruct<Enum::A, 1>::func() {...}
template <>
void MyStruct<Enum::A, 2>::func() {...}
// ...
沒錯,function 偏特化雖然做不到,不過我們依然可以利用其他的語法與特性做到類似的事情,不過腦筋要轉一下就是
沒有留言:
張貼留言