簡體   English   中英

模板基類的子類的模板特化

[英]Template specialization for subclasses of template base class

這個問題有點難以解釋,所以我將從一個例子開始:

我有一個類模板,它將一個類型和一個整數常量作為模板參數,我有許多子類,它們來自該模板的實例化:

template <class V, int i>
struct Base 
{
    static void doSomething() { cout << "something " << i << endl; };
};

struct Child : public Base<int,12>
{
};

我想將這些類與其他模板一起使用(我們稱之為Test),它具有不同類型的特化。 因為對於從Base的任何實例化派生的所有類,行為應該完全相同,所以我想只定義一個處理從Base派生的所有類的Test專門化。

我知道我不能直接專注於Base <V,i>,因為這不會檢測子類。 相反,我的第一種方法是使用Boost的enable_if和類型特征:

// empty body to trigger compiler error for unsupported types
template <class T, class Enabled = void>
struct Test { };

// specialization for ints,
// in my actual code, I have many more specializations here
template <class Enabled>
struct Test <int, Enabled> 
{
    static void test (int dst)
    {
        cout << "Test<int>::test(" << dst << ")" << endl;
    }
};

// this should handle all subclasses of Base,
// but it doesn't compile
template <class T, class V, int i>
struct Test <T, typename enable_if <is_base_and_derived <Base <V,i>, T>>::type>
{
    static void test (const T &dst)
    {
        dst.doSomething();
    }
};

int main (int argc, char **argv)
{
    Test <int>::test (23);
    Test <Child>::test (Child());
    return 0;
}

我們的想法是,專門化應該處理從Base派生的所有類,其中任意值為V和i。 這不起作用,gcc抱怨道:

error: template parameters not used in partial specialization:
error:         ‘V’
error:         ‘i’

我想問題是這種方法需要編譯器嘗試V和i的所有可能組合來檢查它們中的任何一個是否匹配。 現在,我通過向基類添加一些東西解決了這個問題:

template <class V, int i>
struct Base
{
    typedef V VV;
    static constexpr int ii = i;
    static void doSomething() { cout << "something " << i << endl; };
};

這樣,專業化不再需要將V和i作為自由模板參數:

template <class T>
struct Test <T, typename enable_if <is_base_and_derived <Base <typename T::VV, T::ii>, T>>::type>
{
    static void test (const T &dst)
    {
        dst.doSomething();
    }
};

然后它編譯。

現在,我的問題是: 如何在不修改基類的情況下執行此操作? 在這種情況下,這是可能的,因為我自己寫了,但如果我必須在我的測試模板中處理第三方庫代碼,我該怎么辦? 有更優雅的解決方案嗎?

編輯:此外,有人可以給我一個詳細的解釋為什么第一種方法不起作用? 我有一個粗略的想法,但我更願意有一個正確的理解。 :-)

一個簡單的解決方案是讓Base繼承另一個Base_base

struct Base_base
{};

template <class V, int i>
struct Base
 :  public Base_base
{
    static void doSomething() { cout << "something " << i << endl; };
};

template <class T>
struct Test <T, typename enable_if <is_base_and_derived <Base_base, T>>::type>
{
    static void test (const T &dst)
    {
        dst.doSomething();
    }
};

[ 編輯 ]在第三方代碼中,你可以使用如下技巧:

template <class V, int i>
struct Base3rdparty
{
    static void doSomething() { cout << "something " << i << endl; };
};

template <class V, int i>
struct Base
 :  public Base3rdparty<V, i>
{
    typedef V VV;
    static constexpr int ii = i;
};

template <class T>
struct Test <T, typename enable_if <is_base_and_derived <Base <typename T::VV, T::ii>, T>>::type>
{
    static void test (const T &dst)
    {
        dst.doSomething();
    }
};

使用函數重載和decltype

// Never defined:
template<typename T> std::false_type is_Base(T&);
template<class V, int I> std::true_type is_Base(Base<V,I>&);

template<typename IsBase, typename T> struct TestHelper;
template<typename T> struct TestHelper<std::true_type, T>
{
    static void test(const T& dst) { dst.doSomething(); }
};
template<> struct TestHelper<std::false_type, int>
{
    static void test(int dst)
    { std::cout << "Test<int>::test(" << dst << ")" << std::endl; }
};
// ...

template<typename T> struct Test
{
    static void test(const T& dst)
    { TestHelper<decltype(is_Base(std::declval<T&>())), T>::test(dst); }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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