将对象强制转换为其基的子集
Casting an object to a subset of of its bases
我有一个定义如下的类:
template< typename... >
class Base;
template< typename T >
class Base<T>{
//pure virtual functions dependent on T
public:
virtual ~Base() = default;
};
template< typename... Ts >
class Base<Ts...>
: public Base<Ts>...
{
//empty
};
问题是:
- 有没有办法将
Base< T1, T2, T3 >&
投射到Base< T2, T3 >&
? - 有没有办法将
Base< T1, T2, T3 >&
投射到Base< T2, T1, T3 >&
?
编辑:让我在没有模板的情况下改写这个问题。我有一个定义如下的类:
class Base_int{
public:
virtual int f() = 0;
virtual ~Base_int() = default;
};
class Base_float{
public:
virtual float f() = 0;
virtual ~Base_float() = default;
};
class Base_double{
public:
virtual double f() = 0;
virtual ~Base_double() = default;
};
class IFD
: public Base_int
, public Base_float
, public Base_double
{ };
class IF
: public Base_int
, public Base_float
{ };
class FID
: public Base_float
, public Base_int
, public Base_double
{ };
问题是:
- 有没有办法将
IFD&
投射到IF&
? - 有没有办法将
IFD&
投射到FID&
?
编辑2:进一步澄清:我正在影响一个通用的访问者模式实现,我将在通用树容器中使用它。我正在使用mixin(CRTP)模式来实现访问类accept
方法以及访问者visit
方法。这些方法是虚拟的,我需要我在 OP 中发布的层次结构。有一个名为 IVisitor<Ts...>
的基类,它实现了访问Ts...
的访问者的接口。此接口由类IVisitor<T>
组成 - 就像在 OP 中一样。实现IVisitor<Ts...>
的具体访客定义如下:
class ConcreteVisitor : public IVisitor<T1, T2, T2, ...>{
//Implementation of the visit methods defined in IVisitor<Ts...>
virtual void visit( T1& v ) override { /*...*/ }
virtual void visit( T2& v ) override { /*...*/ }
virtual void visit( T3& v ) override { /*...*/ }
}
我突然想到,如果 ConcreteVisitor 可以访问IVisitor<Us...>
中的内容,其中Us...
是Ts...
的子集或排列,那将很有用。为了做到这一点,我需要把它投射到那个基础上——因此问题来了。
在进一步检查了这个问题之后,我意识到我需要一个包装器来适应我的接口的通用访问者。这是我使用的解决方案 - 请参阅IVisitable::adaptVisitor
静态方法:
#include <iostream>
#include <typeinfo>
#include <vector>
//Visitable base class
template< typename >
class Visitable;
//Visitable class interface
template< typename... >
class IVisitor;
//Assures that the visitor type derives from IVisitor
template< typename IVisitor_type >
class IVisitable
: public IVisitable<typename IVisitor_type::derives_from_IVisitor>
{ };
//Implements the Visitor adapter
template< typename Derived, typename Root, typename... Ts >
class VisitorWrapper;
//IVisitable base class
template< typename... Ts >
class IVisitable< IVisitor<Ts...> >{
public:
//Visitor interface type
using IVisitor = IVisitor<Ts...>;
//Visitor adapter type
template< typename F >
class VisitorAdapter;
//Helper function
template< typename F >
static VisitorAdapter<F&&> adaptVisitor( F&& f )
{ return { std::forward<F>(f) }; }
//Accept visitor pure virtual methods
virtual void accept( IVisitor& ) = 0;
virtual void accept( IVisitor& ) const = 0;
virtual void accept( IVisitor&& ) = 0;
virtual void accept( IVisitor&& ) const = 0;
protected:
virtual ~IVisitable() = default;
};
//Implements the visitor adapter of F class
template< typename... Ts >
template< typename F >
class IVisitable<IVisitor<Ts...>>::VisitorAdapter
: public VisitorWrapper< VisitorAdapter<F>, ::IVisitor<Ts...>, Ts... >
//Derives from VisitorWrapper that implements all of the virtual methods
{
public:
template< typename U >
void visit( U&& u ){ f( std::forward<U>(u) ); }
VisitorAdapter( F f_ ) : f(f_) { }
F f;
};
//Basic IVisitor of T
template< typename T >
class IVisitor<T>{
public:
using derives_from_IVisitor = IVisitor;
virtual void visit( T& ) = 0;
virtual void visit( const T& ) = 0;
virtual ~IVisitor() = default;
};
//IVisitor of Ts derives from Visitor<T>
template< typename T, typename... Ts >
struct IVisitor<T, Ts...>
: IVisitor<T>, IVisitor<Ts...>
{
using derives_from_IVisitor = IVisitor;
};
//Visitable base class. Final to prevent errors
template< typename Derived >
struct Visitable final
{
//Extends class wraps the Base class inheritance
template< typename Base >
class extends : public Base
{
public:
//Propagate the IVisitor interface.
using IVisitor = typename Base::IVisitor;
//Prevents incomprehensible errors when visitor doesn't
//define Derived as its visited class
static_assert(
std::is_base_of<::IVisitor<Derived>, IVisitor>::value
, "Base class visitor interface does not support visitation of this type"
);
//Implement accept method via CRTP
virtual void accept( IVisitor& v ) override{
static_cast< ::IVisitor<Derived>& >(v).visit( // Disambiguation
static_cast<Derived&>(*this) // CRTP
);
}
virtual void accept( IVisitor& v ) const override {
static_cast< ::IVisitor<Derived>& >(v).visit( // Disambiguation
static_cast<const Derived&>(*this) // CRTP
);
}
virtual void accept( IVisitor&& v ) override{
static_cast< ::IVisitor<Derived>&& >(v).visit( // Disambiguation
static_cast<Derived&>(*this) // CRTP
);
}
virtual void accept( IVisitor&& v ) const override{
static_cast< ::IVisitor<Derived>&& >(v).visit( // Disambiguation
static_cast<const Derived&>(*this) // CRTP
);
}
protected:
virtual ~extends() = default;
};
~Visitable() = delete;
};
template< typename > struct print_type;
//Uses CRTP to implement visit method of IVisitor
//Consumes the list of Ts... so that the inheritance hierarchy is linear
template<
typename Derived // CRTP
, typename... Rs // Base class (IVisitor<Rs...>)
, typename T // Currently implemented type
, typename... Ts // The rest of types
> class VisitorWrapper< Derived, IVisitor<Rs...>, T, Ts... >
: public VisitorWrapper< Derived, IVisitor<Rs...>, Ts... > //Consume T
{
//Cast to Derived and call visit method
virtual void visit( T& v ){ static_cast<Derived*>(this)->visit(v); }
virtual void visit( const T& v ){ static_cast<Derived*>(this)->visit(v); }
};
//Uses CRTP to implement visit method of IVisitor
template< typename Derived, typename... Rs, typename T >
class VisitorWrapper< Derived, IVisitor<Rs...>, T >
: public IVisitor<Rs...> //IVisitor<Ts...>
{
virtual void visit( T& v ){ static_cast<Derived*>(this)->visit(v); }
virtual void visit( const T& v ){ static_cast<Derived*>(this)->visit(v); }
};
/////////////////////////////////////////////////////
class ABCVisitor
: public IVisitor< class A, class B, class C >
{ };
class ABC : public IVisitable< ABCVisitor >
{};
class A : public Visitable<A>::extends<ABC> {};
class B : public Visitable<B>::extends<ABC> {};
class C : public Visitable<C>::extends<B> {};
int main()
{
auto p = [](const auto& v){ std::cout << typeid(v).name() << std::endl; };
auto printer = ABC::adaptVisitor( p );
A a; B b; C c;
std::vector< ABC* > vs{ &a, &b, &c };
for( const auto& v : vs )
v->accept(printer);
return 0;
}
我不太确定这是否是您要找的,但在这里。我会将基类的accept
方法模板化,以便只要访问者具有正确的概念,它们就可以接受任何访问者。特别:
#include <iostream>
template <class Derived>
struct Base {
// templated visitor so that it can take any argument as long as it has the right concept
template <class Visitor>
void accept(Visitor& visitor) {
visitor.visit(static_cast<Derived&>(*this));
}
};
struct T1
: Base<T1> {};
struct T2
: Base<T2> {};
struct T3
: Base<T3> {};
struct Visitor1 {
void visit(T1& t1) {
std::cout << "Visiting T1 from Visitor1" << std::endl;
}
void visit(T2& t2) {
std::cout << "Visiting T2 from Visitor1" << std::endl;
}
};
struct Visitor2 {
void visit(T1& t1) {
std::cout << "Visiting T1 from Visitor2" << std::endl;
}
void visit(T2& t2) {
std::cout << "Visiting T2 from Visitor2" << std::endl;
}
void visit(T3& t3) {
std::cout << "Visiting T3 from Visitor2" << std::endl;
}
};
int main(int argc, const char * argv[]) {
Visitor1 visitor1;
Visitor2 visitor2;
T1 t1;
T2 t2;
T3 t3;
t1.accept(visitor1);
t1.accept(visitor2);
t2.accept(visitor1);
t2.accept(visitor2);
t3.accept(visitor2);
// t3.accept(visitor1); // triggers a compilation error as visitor1 cannot handle T3 types
}
这样,您就不再需要对访客类进行任何转换。
我认为您不需要使用排列参数投射给访问者来完成您想要的,您唯一需要的是额外的抽象级别 - 可变参数模板包装器给您的访问者。找到下面的代码:
struct VisitorParent {
virtual ~VisitorParent() = default;
};
template <class T>
struct VisitorImpl: virtual VisitorParent {
virtual void visit(T &t) {
//...
}
};
template <class... Ts>
struct Visitor: virtual VisitorImpl<Ts>... { };
template <class T>
struct VisitorWrapperImpl {
VisitorParent *vp;
VisitorWrapperImpl(VisitorParent *vp): vp(vp) {}
void visit(T &t) {
VisitorImpl<T> *cvi = dynamic_cast<VisitorImpl<T> *>(vp);
if (cvi) {
cvi->visit(t);
}
}
};
template <class... Ts>
struct VisitorWrapper: VisitorWrapperImpl<Ts>... {
VisitorWrapper(VisitorParent *vp): VisitorWrapperImpl<Ts>(vp)... { }
template <class T>
void visit(T &t) {
VisitorWrapperImpl<T>::visit(t);
}
};
int main() {
Visitor<int, char, float> v;
VisitorWrapper<char,float> vw(&v);
char c;
vw.visit(c);
}
另一个想法是让 accept 方法采用访问者的基类之一。这样,您可以将任何访问者传递给 accept 方法,因为所有访问者都可以强制转换为单个基 visitor 类。我相信这对你有用:
#include <iostream>
// one of the base classes of your concrete visitors
template <class T>
struct VisitorUnit {
virtual void visit(T& t) = 0;
};
// the visitor interface which will be implemented by concrete visitors
template <class... T>
struct Visitor
: VisitorUnit<T>... {
};
// the base class of your leaf classes
template <class Derived>
struct Base {
void accept(VisitorUnit<Derived>& visitor) {
visitor.visit(static_cast<Derived&>(*this));
}
};
struct T1: Base<T1>{};
struct T2: Base<T2>{};
struct T3: Base<T3>{};
struct Visitor1
: Visitor<T1, T2, T3> {
void visit(T1& t) override {
std::cout << "T1 from Visitor1" << std::endl;
}
void visit(T2& t) override {
std::cout << "T2 from Visitor1" << std::endl;
}
void visit(T3& t) override {
std::cout << "T3 from Visitor1" << std::endl;
}
};
struct Visitor2
: Visitor<T3, T2> {
void visit(T2& t) override {
std::cout << "T2 from Visitor2" << std::endl;
}
void visit(T3& t) override {
std::cout << "T3 from Visitor2" << std::endl;
}
};
int main(int argc, const char * argv[]) {
T1 t1;
T2 t2;
T3 t3;
Visitor1 visitor1;
Visitor2 visitor2;
visitor1.visit(t1);
visitor1.visit(t2);
visitor1.visit(t3);
visitor2.visit(t2);
visitor2.visit(t3);
}
- 防止主数据类型C++的隐式转换
- 模板参数替换失败,并且未完成隐式转换
- 努力将整数转换为链表。不知道我在这里做错了什么
- HEX值到wchar_t字符(UTF-8)的转换
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将 Qvector<uint8_t> 转换为 QString
- 如何在cuSparse中使用cusparseXcoo2csr从coo转换为csc
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 在c++中使用nlohmann从类到json的转换
- 从"int*"强制转换为"unsigned int"会丢失精度错误
- 将Integer转换为4字节的unsined字符矢量(按大端字节顺序)
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 如何使用OpenCV将RBG图像转换为HSV,并将H、S和V值保存为C++中的3个独立图像
- 复制列表初始化的隐式转换的等级是多少
- 正在将指针转换为范围
- 如何防止 c++ 在从浮点型转换为双精度型(不适用于 IO)时添加额外的小数?
- 将 std::variant 转换为另一个具有类型子集的 std::variant
- 如何将C++位集中的位的范围子集转换为数字
- 将向量的子集<uint8_t>转换为整数
- 将对象强制转换为其基的子集