我怎么能取消一个我不知道数据类型的 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*,你不能。但是,这里有两种可能的解决方案(具有不同程度的侵入性):

  1. 您还可以通过某种方式对类型进行编码,例如使用枚举,并使用它 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.
    }
}
  1. 使您的类型多态(使用虚函数和公共基础 class)。而不是 void* 使 pointer 成为指向公共基础 class 的指针,您可以 dynamic_cast 指向具体类型。

不过我要指出,通常在设计良好的程序中,类型的多态使用不需要知道具体类型。考虑使用虚函数或 std::variant.