[英]c++, can I enable several trait class specializations using enable_if instead of copy-paste?
因此,我有一個非模板base
類,其中包含其方法的“默認”設置。 然后,我嘗試對模板化類使用繼承。 這是示例代碼片段,用於說明。
// enums for as a template selector
enum class version
{
ver1,
ver2,
ver3
};
// Base class with fabricated methods
struct base
{
virtual void propertyOne()
{
// some default action
}
virtual void propertyTwo()
{
// some default action
}
};
// derived class
template <version V>
struct derived : public base
{
virtual void propertyOne()
{
helper< One, V >();
}
virtual void propertyTwo()
{
helper< Two, V >();
}
}
我正在使用一個輔助函數來對類特征中使用的不同“字段”執行“通用”算法。
例如:字段與此相似
struct field
{
int thingone;
constexpr field(int i):thingone(i){}
};
在c ++ 11中,為了給字段實例提供外部鏈接,我將它們包裝為另一個結構的靜態成員(c ++ 14放寬了這些規則,哦)。 我這樣做的全部原因是因為我需要它的常量表達式值(例如,需要成員變量thone作為另一種方法的模板參數,該方法要求它是常量表達式)。
struct fields
{
static constexpr field One{1};
static constexpr field Two{2};
};
// defining trait class from structure above
template< const field& T, revision R >
class fieldTraits;
// sample fieldTrait definitions for illustrative purposes
template< >
class fieldTraits< fields::One, revision::ver3>
{
public:
// Let's say I have common field names
// with different constants that I want to plug
// into the "helper" algorithm
static constexpr size_t field_val = 1;
};
template< >
class fieldTraits< fields::Two, revision::ver1>
{
public:
// Let's say I have common field names
// with different constants that I want to plug
// into the "helper" algorithm
static constexpr size_t field_val = 1;
};
// Main guts of the class methods above
template< const field& F, revision R, typename TT = traitClass<F,R> >
void helper()
{
// Let's pretend I'm doing something useful with that data
std::cout << F.thingone << std::endl;
std::cout << TT::field_val << std::endl;
}
我遇到的問題是試圖實例化例如
derived<revision::rev1> l_derived;
由於我只為ver3
定義了trait類, ver3
如果不為ver1
和ver2
顯式定義trait類,就無法實例化該類。 但是,如果traits類與ver1
- ver 3
完全相同,是否有任何一種enable_if條件必須使該模板類對所有revs <= ver3
有效?
我在traits_type標頭中找不到任何內容,該標頭主要提供編譯時“類型”檢查,例如std::is_same
等。
我知道一種選擇是復制粘貼ver1
- ver3
的特征類,但這似乎是多余的,因為我想避免復制粘貼重復的代碼。
另一個選擇是為每個修訂版本創建不同的類,並利用動態多態性在這里可以為每個修訂版本定義一個類。 然后,我只需要在需要的地方包括特征修訂。 例如,
class derived_ver1 : public base
{
virtual void propertyOne()
{
helper< fields::One, revision::ver1 >();
}
virtual void propertyTwo()
{
helper< fields::Two, revision::ver1 >();
}
};
class derived_ver2 : public derived:ver1
{
virtual void propertyTwo()
{
helper< fields::Two, revision::ver2 >();
}
};
class derived_ver3 : public derived:ver2
{
virtual void propertyTwo()
{
helper< Two, revision::ver3 >();
}
};
在此示例中, propertyOne()
可以將版本1的traits類重新用於版本2和版本3,因為它在版本1之后沒有更改(並避免了特性的復制粘貼)。
有沒有我可以采用的更好的設計?
總結:有一種方法可以使用我的原始模板繼承並使用某些模板功能(例如std::enable_if
)將trait類重用於未定義的修訂版。 而不是為每個修訂版明確定義特征(導致復制粘貼)。
還是使用動態多態性的第二種方法是執行此操作的更好方法(我讀過,帶有它的vtable查找成本增加了)?
我很難理解你想要什么。 請修改您的問題以檢查詳細信息( version
和revision
是否相同? fieldTraits
和traitsClass
是否相同?)。
無論如何,如果我理解正確,則想為
template <const field& T, revision R>
class fieldTraits;
當R
為val1
或val2
或val3
,可能還有其他專門針對單個跟隨值的特性。
假設您有四個修訂版本
enum class revision { ver1, ver2, ver3, ver4 };
您可以聲明fieldTraits
(作為struct
,以使其更短),添加一個bool
默認模板參數,該參數說明是否R <= revision::ver3
template <field const & T, revision R, bool = (R <= revision::ver3)>
struct fieldTraits;
現在您可以為ver1
, ver2
和ver3
開發一個專業化ver3
template <field const & T, revision R>
struct fieldTraits<T, R, true>
{ static constexpr size_t field_val = 1; };
和ver4
的專業化
template <field const & T>
struct fieldTraits<T, revision::ver4>
{ static constexpr size_t field_val = 2; };
以下是一個簡化但完整的示例
#include <iostream>
enum class revision { ver1, ver2, ver3, ver4 };
struct field
{
int thingone;
constexpr field (int i) : thingone(i)
{ }
};
template <field const & T, revision R, bool = (R <= revision::ver3)>
struct fieldTraits;
// version ver1, ver2, ver3 cases
template <field const & T, revision R>
struct fieldTraits<T, R, true>
{ static constexpr size_t field_val = 1; };
// version ver4 case
template <field const & T>
struct fieldTraits<T, revision::ver4>
{ static constexpr size_t field_val = 2; };
static constexpr field f{1};
int main ()
{
std::cout << "ver1: " << fieldTraits<f, revision::ver1>::field_val
<< std::endl;
std::cout << "ver2: " << fieldTraits<f, revision::ver2>::field_val
<< std::endl;
std::cout << "ver3: " << fieldTraits<f, revision::ver3>::field_val
<< std::endl;
std::cout << "ver4: " << fieldTraits<f, revision::ver4>::field_val
<< std::endl;
}
該打印
ver1: 1
ver2: 1
ver3: 1
ver4: 2
-編輯-
根據OP的評論,我提出了一些不同的解決方案
template <field const & T, revision R, typename = std::true_type>
struct fieldTraits;
// version ver1, ver2, ver3 cases
template <field const & T, revision R>
struct fieldTraits<T, R, std::integral_constant<bool, (R <= revision::ver3)>>
{ static constexpr size_t field_val = 1; };
// version ver4 case
template <field const & T>
struct fieldTraits<T, revision::ver4>
{ static constexpr size_t field_val = 2; };
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.