c++ - 通过其接口访问可变参数模板结构
问题描述
有一个类的层次结构:
template<typename T>
class FeatureInterface1 {
public:
void f1( void ) { static_cast<T&>(*this)._f1(); }
}
class Feature1 : public FeatureInterface1<Feature1> {
/* Allow interface class to access private elements */
friend class FeatureInterface<Feature1>;
private:
void _f1(void) { /* Do something there */ }
}
template<typename T>
class FeatureInterface2 {
public:
void f2( void ) { static_cast<T&>(*this)._f2(); }
}
class Feature2 : public FeatureInterface2<Feature2> {
/* Allow interface class to access private elements */
friend class FeatureInterface<Feature2>;
private:
void _f2(void) { /* Do something there */ }
}
然后是一个可变参数数据类:
template<typename... FEATURES> class Device {};
template<typename FEATURE, typename... OTHERS>
class Device<FEATURE, OTHERS...> : public Device<OTHERS...> {
public:
/* Contructor */
Device(FEATURE feature, OTHERS... others)
: Device<OTHERS...>(others...),
m_feature( feature ) {
}
private:
FEATURE m_feature;
};
最后是在编译时制作的全功能对象:
Device<Feature1, Feature2> device;
任务是设计一个get<>()
函数,该函数使用其接口返回指向特定对象的指针。示例用法:
FeatureInterface1<Feature1>* ptr_f = get<FeatureInterface1<Feature1>>(device);
换句话说,类似get<0>
, get<1>
... 的访问器是std::tuple
接口类定义的而不是索引定义的。
我的想法是std::enable_if
与std::is_base_of
...结合使用
灵感来自https://eli.thegreenplace.net/2014/variadic-templates-in-c/
我会很高兴任何愿意帮助我的人。提前致谢!
解决方案
这实际上非常简单if constexpr
:
template<typename FEATURE, typename... OTHERS>
class Device<FEATURE, OTHERS...> : public Device<OTHERS...> {
public:
...
template <typename FEATURE_INTERFACE>
FEATURE_INTERFACE& get()
{
if constexpr (std::is_base_of_v<FEATURE_INTERFACE, FEATURE>)
return m_feature;
else
return Device<OTHERS...>::template get<FEATURE_INTERFACE>();
}
...
};
请注意,如果Device
不支持请求的接口,您将收到编译错误。但是,如果您想要 a ,那么nullptr
使用 empty 的额外专业化也不是那么难Device
:
template<>
class Device<> {
public:
template <typename FEATURE_INTERFACE>
FEATURE_INTERFACE* get()
{
return nullptr;
}
};
然后只需更改主要实现以返回一个指针:
template <typename FEATURE_INTERFACE>
FEATURE_INTERFACE* get()
{
if constexpr (std::is_base_of_v<FEATURE_INTERFACE, FEATURE>)
return &m_feature;
else
return Device<OTHERS...>::template get<FEATURE_INTERFACE>();
}
我使用成员函数而不是非成员函数,因为在我看来,这种实现方式更简单,而且我个人也不喜欢那些非成员的朋友获取者:)。此外,正如 Red.Wave 在评论中提到的那样,使用成员制作非成员 getter 非常容易:
template <typename FEATURE_INTERFACE, typename... FEATURES>
FEATURE_INTERFACE* get(Device<FEATURES...>& device)
{
return device.template get<FEATURE_INTERFACE>();
}
您可能还想为所有这些 getter 添加 const 重载以确保完整性。
推荐阅读
- javascript - JavaScript - 词法作用域、闭包和谷歌开发者工具
- visual-studio - 在 Azure Devops Pipeline 中构建和发布 ASP.net 核心时,如何包含许可证文件?
- javascript - 我可以拦截表单动作吗?
- c++ - 在配置步骤中通过 CMake 检查数据类型大小的目的是什么?
- c++ - 为什么资源释放后仍然可以访问并且程序没有崩溃?
- javascript - 如何在 if-else 语句代码块中获取先前的变量?
- string - 如何从图像中获取“var svgData”?
- typescript - Nest.js RangeError:超出最大调用堆栈大小
- c# - 在 SQL 选择语句中从文本框中传递整数值
- mysql - 错误代码:1305。FUNCTION ticket.IIF 不存在