簡體   English   中英

C ++,我可以使用enable_if代替復制粘貼來啟用多個特征類專業化嗎?

[英]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如果不為ver1ver2顯式定義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查找成本增加了)?

我很難理解你想要什么。 請修改您的問題以檢查詳細信息( versionrevision是否相同? fieldTraitstraitsClass是否相同?)。

無論如何,如果我理解正確,則想為

template <const field& T, revision R>
class fieldTraits;

Rval1val2val3 ,可能還有其他專門針對單個跟隨值的特性。

假設您有四個修訂版本

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;

現在您可以為ver1ver2ver3開發一個專業化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.

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