2022年6月17日

[C++] Partial Template Specialization of class Member Function

事情是這樣的,有人問我他想做到這件事:

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 偏特化雖然做不到,不過我們依然可以利用其他的語法與特性做到類似的事情,不過腦筋要轉一下就是

沒有留言:

張貼留言