c++,我可以使用 enable_if 而不是复制粘贴来启用多个特征类特化吗?

标签 c++ c++11 templates polymorphism typetraits

所以我有一个非模板 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 放宽了这些规则,哦,好吧)。我这样做的全部原因是因为我需要它的常量表达式值(例如,成员变量 thingone 需要作为另一个方法的模板参数,这需要它是一个常量表达式)。

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 定义了特征类, 我无法在不为 ver1 定义特征类的情况下实例化该类, 和 ver2明确地。但是如果特征类完全相同,比如说 ver1 - ver 3 , 是任何类型的 enable_if 条件我必须使这个模板类对所有 revs <= ver3 有效?

我在 traits_type header 中找不到任何内容,它主要提供编译时“类型”检查,例如 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 中的特征类重用于修订版 2 和修订版 3,因为它没有更改过去的修订版 1(并避免复制粘贴特征)。

我可以采用更好的设计吗?

总结:有没有一种方法可以使用我的原始模板继承并使用某些模板功能(例如 std::enable_if )为未定义的修订重用特征类。而不是为每个修订明确定义特征(这会导致复制粘贴)。

或者使用动态多态性的第二种方法是否是更好的方法(我读到,它增加了随附的 vtable 查找的成本)?

最佳答案

我很难理解你想要什么;请修改您的问题以检查详细信息(versionrevision 是一样的吗?fieldTraitstraitsClass 是一样的吗?)。

无论如何,如果我理解正确的话,你想为

定义一个特化
template <const field& T, revision R>
class fieldTraits;

Rval1val2val3并且,也许还有针对单个以下值的其他特化。

假设你有四次修改

enum class revision { ver1, ver2, ver3, ver4 };

可以声明fieldTraits (作为 struct ,使其更短)添加 bool表示 if R <= revision::ver3 的默认模板参数

template <field const & T, revision R, bool = (R <= revision::ver3)>
struct fieldTraits;

现在您可以为 ver1 开发特化, ver2ver3

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; };

关于c++,我可以使用 enable_if 而不是复制粘贴来启用多个特征类特化吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50223447/

相关文章:

javascript - AngularJS - 带有动态模板的指令

c++ - 什么是自定义调用约定?

c++ - 菜单中的逻辑错误和读取功能以保存和读取文件

c++ - 派生自同一类但不共享公共(public)方法的两个对象的类设计

c++ - 从另一个文件读取时写入文件

c++ - 如何初始化一个很长的数组?

c++11 - unique_ptr堆和栈分配

c++11 - fbthrift (facebook thrift) 稳定版发布了吗?

c++ - 条件分支的模板和优化

c++ - 模板函数中任意迭代器的值类型