如何在类级别存储从构造函数收集的类型信息,以便在强制转换中使用
How to store type information, gathered from a constructor, at the class level to use in casting
我正在尝试编写一个类,我可以存储和使用类型信息,而不需要模板参数。
我想这样写:
class Example
{
public:
template<typename T>
Example(T* ptr)
: ptr(ptr)
{
// typedef T EnclosedType; I want this be a avaialable at the class level.
}
void operator()()
{
if(ptr == NULL)
return;
(*(EnclosedType*)ptr)(); // so i can cast the pointer and call the () operator if the class has one.
}
private:
void* ptr;
}
我不是在问如何编写一个is_functor()类。
我想知道如何在构造函数中获取类型信息并将其存储在类级别。如果这是不可能的,一个不同的解决方案将是赞赏的。
我认为这是一个很好的和有效的问题,但是,除了在类级别使用模板参数之外,没有一般的解决方案。你在问题中试图实现的——在函数中使用typedef
,然后在整个类中访问它——是不可能的。
类型擦除
只有当你对构造函数参数施加某些限制时,才有一些替代方法。在这方面,这里有一个类型擦除的示例,其中某些给定对象的operator()
存储在std::function<void()>
变量中。
struct A
{
template<typename T>
A(T const& t) : f (std::bind(&T::operator(), t)) {}
void operator()() const
{
f();
}
std::function<void()> f;
};
struct B
{
void operator()() const
{
std::cout<<"hello"<<std::endl;
}
};
int main()
{
A(B{}).operator()(); //prints "hello"
}
演示但是,请注意这种方法的假设:假设所有传递的对象都有一个给定签名(这里是void operator()
)的操作符,该操作符存储在std::function<void()>
中(关于存储成员函数,请参阅这里)。
从某种意义上说,类型擦除类似于"没有基类的继承"——可以为所有构造函数形参类使用带有虚括号操作符的公共基类,然后将基类指针传递给构造函数。
struct A_parameter_base
{
void operator()() const = 0;
};
struct B : public A_parameter_base
{
void operator()() const { std::cout<<"hello"<<std::endl; }
};
struct A
{
A(std::shared_ptr<A_parameter_base> _p) : p(_p) {}
void operator()()
{
p->operator();
}
std::shared_ptr<A_parameter_base> p;
}
这与您的问题中的代码相似,只是它不使用void
指针,而是指向特定基类的指针。
两种方法,类型擦除和继承,在它们的应用程序中是相似的,但是类型擦除可能在摆脱公共基类时更方便。但是,继承方法还有一个优点,那就是可以通过多个分派
恢复原始对象。这也显示了两种方法的局限性。如果您的操作符不是void
,而是返回一些未知的变化类型,则不能使用上述方法,而必须使用模板。继承的平行点是:你不能有虚函数模板。
实际的答案是在std::function<void()>
中存储类的副本或std::ref
包装的类的伪引用。
std::function
类型擦除它存储的东西归结为3个概念:复制,销毁和调用一个固定的签名。(还有cast- to-original-type和typeid,更隐晦)
它所做的是在构造时记住如何对传入的类型执行这些操作,并以能够对其执行这些操作的方式存储副本,然后忘记该类型的其他所有内容。
你不能用这种方式记住一个类型的所有信息。但是,几乎任何具有固定签名的操作,或者可以通过固定签名操作进行中介的操作,都可以被类型擦除到。
第一种典型的方法是为这些操作创建一个私有纯接口,然后创建一个模板实现(在传递给tor的类型上模板化),该模板实现该特定类型的每个操作。执行类型擦除的类然后存储一个指向私有接口的(智能)指针,并将其公共操作转发给它。
第二种典型的方法是存储void*
或char类型的缓冲区,以及一组指向实现这些操作的函数的指针。指向函数的指针既可以本地存储在类型擦除类中,也可以存储在为每个擦除类型静态创建的helper结构中,并且指向helper结构的指针存储在类型擦除类中。存储函数指针的第一种方式类似于c风格的对象属性,第二种方式类似于手动虚函数表。
在任何情况下,函数指针通常采用一个(或多个)void*
,并知道如何将它们转换回正确的类型。它们是在知道类型的actor中创建的,或者作为template
函数的实例,或者作为本地无状态lambda,或者间接地。
你甚至可以将两者混合使用:静态pimpl实例指针采用void*
或其他类型。
通常使用std::function
就足够了,与使用std::function
相比,手动书写类型擦除很难正确。
前两个答案的另一个版本-更接近您当前的代码:
class A{
public:
virtual void operator()=0;
};
template<class T>
class B: public A{
public:
B(T*t):ptr(t){}
virtual void operator(){(*ptr)();}
T*ptr;
};
class Example
{
public:
template<typename T>
Example(T* ptr)
: a(new B<T>(ptr))
{
// typedef T EnclosedType; I want this be a avaialable at the class level.
}
void operator()()
{
if(!a)
return;
(*a)();
}
private:
std::unique_ptr<A> a;
}
- 正在查找文档以获得PS4平台的C++中的设备信息
- 防止主数据类型C++的隐式转换
- 模板参数替换失败,并且未完成隐式转换
- 努力将整数转换为链表。不知道我在这里做错了什么
- HEX值到wchar_t字符(UTF-8)的转换
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将 Qvector<uint8_t> 转换为 QString
- 如何在cuSparse中使用cusparseXcoo2csr从coo转换为csc
- 是否可以将信息从XML文件转换为CPP
- 为什么类型转换对象不会更改其地址?有关对象类型的信息存储在哪里?
- 将人类可读日期转换为毫秒,然后再转换回来,而不会丢失信息
- 如何将进程信息转换为WTS_PROCESS_INFO
- 如何避免在通过队列传递信息时向下转换
- 如何将提取的光栅信息转换为可由opencv库处理的格式
- 没有上下文类型信息的重载函数 |无法根据转换为类型 'int' 解析重载函数'swap'
- 如何将Visual Studio . net 2003项目构建信息转换为VS命令提示符
- 如何使用C++将.gis(地理信息系统)文件转换为.img格式
- 如何在类级别存储从构造函数收集的类型信息,以便在强制转换中使用
- 重载大于操作符的操作符将用户定义类型强制转换为原语,信息丢失
- 从 Iplimage 转换为 Mat 不会保留深度信息