我怎么能取消一个我不知道数据类型的 void* 呢?
How could I uncast a void* that I don't know the data type?
我有两个不同的结构std::multimap
。我想做这样的事情,但是,我怎么能取消转换我不知道数据类型的 void*
?
struct Data{
std::multimap<uint64_t,uint64_t, std::greater<uint64_t>> b;
std::multimap<uint64_t,uint64_t, std::less<uint64_t>> s;
};
Data data;
void do_something(bool c){
void* pointer;
uint64_t cumulative = 0;
if(c){
pointer = &data.b;
} else {
pointer = &data.s;
}
/* Here I don't know if pointer is
* std::multimap<uint64_t,uint64_t, std::greater<uint64_t>>
* or
* std::multimap<uint64_t,uint64_t, std::less<uint64_t>>
*/
for(auto it = (*pointer).begin(); it != (*pointer).end(); ++it){
cumulative += it->second;
}
}
谢谢
How could I uncast a void* that I don't know the data type?
你不能这样做。
您只能转换为您知道的类型。
对于这样的事情,您可以编写一个在任何范围内运行的函数模板:
template<class Range>
void do_something_template(Range& r){
// do something
}
void do_something(bool c){
uint64_t cumulative = c
? do_something_template(data.b)
: do_something_template(data.s);
就是说,对于您在这种特殊情况下所做的事情,已经有一个标准算法:std::accumulate
,无需重写。
如果没有其他信息,您将不知道基础类型是。因此,将 void*
转换为任何类型指针类型都容易出错。
您可以使用不同的策略来处理您的情况。
template <typename Iter>
uint64_t do_something(Iter start, Iter end)
{
uint64_t cumulative = 0;
for(auto it = start; it != end; ++it){
cumulative += it->second;
}
return cumulative;
}
void do_something(bool c)
{
uint64_t cumulative = 0;
if(c)
{
cumulative = do_something(data.b.begin(), data.b.end());
}
else
{
cumulative = do_something(data.s.begin(), data.s.end());
}
}
您可以使用std::accumulate
来简化第一个函数。
template <typename Iter>
uint64_t do_something(Iter start, Iter end)
{
return std::accumulate(start, end, 0);
}
你不能取消引用空指针,但在你的情况下你可以这样做:
template<typename Container>
uint64_t do_something_helper(const Container& container)
{
uint64_t cumulative = 0;
for (const auto& item : container) {
cumulative += item.second;
}
return cumulative;
}
void do_something(bool c)
{
uint64_t cumulative = [&]() {
if (c) {
return do_something_helper(data.b);
}
else {
return do_something_helper(data.s);
}
}();
// Do something with cumulative
}
而且。这是 C++17 中的 std::any
:
void do_something(bool c)
{
std::any container;
if (c) {
container = data.b;
}
else {
conainter = data.s;
}
try {
auto* pCont = std::any_cast<decltype(data.b)>( &container );
for ( ... ) {
// compute cumulative
}
}
catch(const std::bad_any_cast&) {
auto* pCont = std::any_cast<decltype(data.s)>( &container );
for ( ... ) {
// compute cumulative
}
}
}
但对我来说,第一个解决方案看起来比第二个好一点:)
只有 void*
,你不能。但是,这里有两种可能的解决方案(具有不同程度的侵入性):
- 您还可以通过某种方式对类型进行编码,例如使用枚举,并使用它
static_cast
返回具体类型。
struct A {};
struct B {};
enum class Type
{
A,
B,
};
void do_something(bool c)
{
A a;
B b;
void* pointer;
Type type;
if (c)
{
pointer = &a;
type = Type::A;
}
else
{
pointer = &b;
type = Type::B;
}
if (type == Type::A)
{
A* concrete = static_cast<A*>(pointer);
// Use concrete here as A.
}
else if (type == Type::B)
{
B* concrete = static_cast<B*>(pointer);
// Use concrete here as B.
}
}
- 使您的类型多态(使用虚函数和公共基础 class)。而不是
void*
使 pointer
成为指向公共基础 class 的指针,您可以 dynamic_cast
指向具体类型。
不过我要指出,通常在设计良好的程序中,类型的多态使用不需要知道具体类型。考虑使用虚函数或 std::variant
.
我有两个不同的结构std::multimap
。我想做这样的事情,但是,我怎么能取消转换我不知道数据类型的 void*
?
struct Data{
std::multimap<uint64_t,uint64_t, std::greater<uint64_t>> b;
std::multimap<uint64_t,uint64_t, std::less<uint64_t>> s;
};
Data data;
void do_something(bool c){
void* pointer;
uint64_t cumulative = 0;
if(c){
pointer = &data.b;
} else {
pointer = &data.s;
}
/* Here I don't know if pointer is
* std::multimap<uint64_t,uint64_t, std::greater<uint64_t>>
* or
* std::multimap<uint64_t,uint64_t, std::less<uint64_t>>
*/
for(auto it = (*pointer).begin(); it != (*pointer).end(); ++it){
cumulative += it->second;
}
}
谢谢
How could I uncast a void* that I don't know the data type?
你不能这样做。
您只能转换为您知道的类型。
对于这样的事情,您可以编写一个在任何范围内运行的函数模板:
template<class Range>
void do_something_template(Range& r){
// do something
}
void do_something(bool c){
uint64_t cumulative = c
? do_something_template(data.b)
: do_something_template(data.s);
就是说,对于您在这种特殊情况下所做的事情,已经有一个标准算法:std::accumulate
,无需重写。
如果没有其他信息,您将不知道基础类型是。因此,将 void*
转换为任何类型指针类型都容易出错。
您可以使用不同的策略来处理您的情况。
template <typename Iter>
uint64_t do_something(Iter start, Iter end)
{
uint64_t cumulative = 0;
for(auto it = start; it != end; ++it){
cumulative += it->second;
}
return cumulative;
}
void do_something(bool c)
{
uint64_t cumulative = 0;
if(c)
{
cumulative = do_something(data.b.begin(), data.b.end());
}
else
{
cumulative = do_something(data.s.begin(), data.s.end());
}
}
您可以使用std::accumulate
来简化第一个函数。
template <typename Iter>
uint64_t do_something(Iter start, Iter end)
{
return std::accumulate(start, end, 0);
}
你不能取消引用空指针,但在你的情况下你可以这样做:
template<typename Container>
uint64_t do_something_helper(const Container& container)
{
uint64_t cumulative = 0;
for (const auto& item : container) {
cumulative += item.second;
}
return cumulative;
}
void do_something(bool c)
{
uint64_t cumulative = [&]() {
if (c) {
return do_something_helper(data.b);
}
else {
return do_something_helper(data.s);
}
}();
// Do something with cumulative
}
而且。这是 C++17 中的 std::any
:
void do_something(bool c)
{
std::any container;
if (c) {
container = data.b;
}
else {
conainter = data.s;
}
try {
auto* pCont = std::any_cast<decltype(data.b)>( &container );
for ( ... ) {
// compute cumulative
}
}
catch(const std::bad_any_cast&) {
auto* pCont = std::any_cast<decltype(data.s)>( &container );
for ( ... ) {
// compute cumulative
}
}
}
但对我来说,第一个解决方案看起来比第二个好一点:)
只有 void*
,你不能。但是,这里有两种可能的解决方案(具有不同程度的侵入性):
- 您还可以通过某种方式对类型进行编码,例如使用枚举,并使用它
static_cast
返回具体类型。
struct A {};
struct B {};
enum class Type
{
A,
B,
};
void do_something(bool c)
{
A a;
B b;
void* pointer;
Type type;
if (c)
{
pointer = &a;
type = Type::A;
}
else
{
pointer = &b;
type = Type::B;
}
if (type == Type::A)
{
A* concrete = static_cast<A*>(pointer);
// Use concrete here as A.
}
else if (type == Type::B)
{
B* concrete = static_cast<B*>(pointer);
// Use concrete here as B.
}
}
- 使您的类型多态(使用虚函数和公共基础 class)。而不是
void*
使pointer
成为指向公共基础 class 的指针,您可以dynamic_cast
指向具体类型。
不过我要指出,通常在设计良好的程序中,类型的多态使用不需要知道具体类型。考虑使用虚函数或 std::variant
.