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