通过其接口访问可变参数模板结构
Access variadic template structure by its interface
存在 classes 的层次结构:
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 */ }
}
然后就是一个可变数据class:
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<>()
函数,该函数 returns 使用它的接口指向特定对象的指针。 示例用法:
FeatureInterface1<Feature1>* ptr_f = get<FeatureInterface1<Feature1>>(device);
换句话说,类似于 get<0>
、get<1>
... std::tuple
的访问器,但接口是 class 定义的,而不是索引定义的。
我的想法是将 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
不支持请求的接口,您将收到编译错误。但是,如果你想要一个 nullptr
而不是那么难,或者对空 Device
:
进行额外的专业化
template<>
class Device<> {
public:
template <typename FEATURE_INTERFACE>
FEATURE_INTERFACE* get()
{
return nullptr;
}
};
然后只需将主要实现更改为 return 指针:
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>();
}
我使用成员函数而不是非成员函数,因为在我看来,这样实现起来更简单,而且我个人也不喜欢那些非成员朋友 getters :)。此外,正如 Red.Wave 在评论中提到的,使用成员 getter 很容易使非成员成为成员:
template <typename FEATURE_INTERFACE, typename... FEATURES>
FEATURE_INTERFACE* get(Device<FEATURES...>& device)
{
return device.template get<FEATURE_INTERFACE>();
}
为了完整性,您可能还想向所有这些 getter 添加常量重载。
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 ) {
}
template<class T>
friend std::enable_if_t<std::is_base_of<T, FEATURE>{}, T&>
get( Device& d ){ return d.m_feature; }
template<class T>
friend std::enable_if_t<std::is_base_of<T, FEATURE>{}, T const&>
get( Device const& d ){ return d.m_feature; }
应该这样做。
您可能需要一些 template<class T,class U> decltype(auto) get(U&u, ...){ return get<T>(u); }
来启用 ADL(但我不喜欢给出的错误消息),或者一个返回到 get_impl
或其他东西的 get-template。
存在 classes 的层次结构:
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 */ }
}
然后就是一个可变数据class:
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<>()
函数,该函数 returns 使用它的接口指向特定对象的指针。 示例用法:
FeatureInterface1<Feature1>* ptr_f = get<FeatureInterface1<Feature1>>(device);
换句话说,类似于 get<0>
、get<1>
... std::tuple
的访问器,但接口是 class 定义的,而不是索引定义的。
我的想法是将 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
不支持请求的接口,您将收到编译错误。但是,如果你想要一个 nullptr
而不是那么难,或者对空 Device
:
template<>
class Device<> {
public:
template <typename FEATURE_INTERFACE>
FEATURE_INTERFACE* get()
{
return nullptr;
}
};
然后只需将主要实现更改为 return 指针:
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>();
}
我使用成员函数而不是非成员函数,因为在我看来,这样实现起来更简单,而且我个人也不喜欢那些非成员朋友 getters :)。此外,正如 Red.Wave 在评论中提到的,使用成员 getter 很容易使非成员成为成员:
template <typename FEATURE_INTERFACE, typename... FEATURES>
FEATURE_INTERFACE* get(Device<FEATURES...>& device)
{
return device.template get<FEATURE_INTERFACE>();
}
为了完整性,您可能还想向所有这些 getter 添加常量重载。
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 ) {
}
template<class T>
friend std::enable_if_t<std::is_base_of<T, FEATURE>{}, T&>
get( Device& d ){ return d.m_feature; }
template<class T>
friend std::enable_if_t<std::is_base_of<T, FEATURE>{}, T const&>
get( Device const& d ){ return d.m_feature; }
应该这样做。
您可能需要一些 template<class T,class U> decltype(auto) get(U&u, ...){ return get<T>(u); }
来启用 ADL(但我不喜欢给出的错误消息),或者一个返回到 get_impl
或其他东西的 get-template。