c++ - c++,我可以使用 enable_if 而不是复制粘贴来启用几个特征类专业化吗?
问题描述
所以我有一个非模板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;
由于我只定义了 trait 类,ver3
我无法在不明确定义 trait 类的情况下实例化该类。但是,如果特征类对于-来说是完全相同的,那么是否有任何一种 enable_if 条件我必须使这个模板类对所有人都有效? ver1
ver2
ver1
ver 3
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 中的特征类重用于修订版 2 和修订版 3,因为它没有更改过去的修订版 1(并且避免复制粘贴特征)。
有没有更好的设计我可以接近?
总而言之:有没有办法使用我原来的模板继承并使用一些模板功能(例如std::enable_if
)为未定义的修订重用一个特征类。而不是为每个修订明确定义一个特征(这会导致复制粘贴)。
或者使用动态多态的第二种方法是更好的方法(我读到,增加了 vtable 查找的成本)?
解决方案
我发现很难理解你想要什么;请修改您的问题以检查详细信息(version
并且revision
相同?fieldTraits
并且traitsClass
相同?)。
无论如何,如果我理解正确,您想为
template <const field& T, revision R>
class fieldTraits;
when R
is val1
or val2
or val3
and, may be, other specializations for single following values。
假设您有四个修订版
enum class revision { ver1, ver2, ver3, ver4 };
您可以声明fieldTraits
(作为struct
, 使其更短)添加一个bool
默认模板参数,说明 ifR <= revision::ver3
template <field const & T, revision R, bool = (R <= revision::ver3)>
struct fieldTraits;
现在您可以为ver1
和ver2
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; };
推荐阅读
- django - 为什么 Django 单元测试没有看到引发的异常?
- javascript - Vue 组件在哪里导入?
- visualization - 在 Power BI 图中绘制多条线
- r - 从R中的多个pdf文件中提取数据
- spreadsheet - 如何在谷歌表中将今天()函数的输出作为字符串
- javascript - 保留被拖动的元素
- postgresql - PostgreSQL 表移动平均值
- django - 传入 4 个参数,但被 Django 服务器读取为 5
- html - 为 gmail 编写 HTML 电子邮件。链接的图像显示霓虹蓝背景
- javascript - 片段标识符拉下页面后如何将页面滚动到顶部?