获取已从void *转换的数据类型?

时间:2018-03-04 19:54:37

标签: c++

我有一个有3个参数的功能。第三个参数的数据类型为void*,有两种类型的数据可以通过std::stringFILE*传递。

bool MainDialog::readDataFromUrl(const std::string url, const std::string parameter, void *reply) {
    CURL *curl;
    bool status;
    curl = curl_easy_init();
    if(curl){
        std::string fullUrl = url +  parameter;
        curl_easy_reset(curl);
        curl_easy_setopt(curl, CURLOPT_URL, fullUrl.c_str());
        if(typeid(reply) != typeid(FILE*)){
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &MainDialog::writeFunction);
        }
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, reply);
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L);
        if(curl_easy_perform(curl) != CURLE_OK){
            status = false;
        }
        curl_easy_cleanup(curl);
        status = true;
    }
    return status;
}

使用时:

FILE *file;
file = fopen("jsonData.txt", "wb");
this->readDataFromUrl("http://example.com?api=data", "", (FILE*)file);

以下部分代码检查数据类型并确定它是std::string是否做某事以及它是FILE*做了另一件事。

if(typeid(reply) != typeid(FILE*))
   curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &MainDialog::writeFunction);

是否可以获取转换为 void*的数据类型?

4 个答案:

答案 0 :(得分:4)

不,你无法获得这些信息,这就是为什么人们说将所有内容都转换为void*以将其塞入一个函数的原因并不是类型安全的。据说你已经“删除”了这种类型。

相反,传递std::variant<std::string, FILE*>

如果您是C ++之前的17,请传递boost::variant<std::string, FILE*>

“变体”是“标记联合”的实现,它执行您正在执行的操作,但是以类型安全的方式执行;变体将能够告诉你实际存储了哪种对象。

另一种方法是使用第四个参数作为枚举(或其他类型的“标记”)来描述如何解释第三个参数:

enum reply_type_t {
   STRING,
   FILE_PTR
};

bool MainDialog::readDataFromUrl(
   const std::string& url,
   const std::string& parameter,
   void* reply,
   replyType_t replyType
);

不幸的是,这取决于致电readDataFromUrl以“正确行事”的人。我们可以帮助它以及一些新的重载:

bool MainDialog::readDataFromUrl(
   const std::string& url,
   const std::string& parameter,
   const std::string& reply
)
{
   return readDataFromUrl(url, parameter, (void*)&reply, STRING);
}

bool MainDialog::readDataFromUrl(
   const std::string& url,
   const std::string& parameter,
   const FILE* reply
)
{
   return readDataFromUrl(url, parameter, (void*)reply, FILE_PTR);
}

现在你的调用者只需要直接传递正确的参数,标记就会自动为你完成。

但是,说真的,只需使用变体。

答案 1 :(得分:3)

您不能这样做:typeid运算符允许您在运行时仅使用多态类型区分对象的动态类型,而FILE 是多态类型。在您的代码中,typeid最终会使用void*的类型标识符,这根本不会有任何帮助。

您有几种方法可以满足此要求:

  • 使您可以接受的不同类型的函数重载,或
  • 制作一个不同类型的enum,并将其与void*一起作为单独的参数传递,或者
  • 使用union标记创建enum,创建此联合的实例,并将指针作为void*传递给该函数,或
  • 始终打开回复,即将FILE*读入std::string

如果您可以将函数的签名更改为特定于类型,则第一种方法是理想的。

答案 2 :(得分:0)

不,它无法从void *中获取实际的类型数据。 typeid运算符仅适用于具有至少一个虚方法的类/结构类型的多态类型。

答案 3 :(得分:0)

没有。将其转换为void *后,类型信息将丢失。这里通常的方法是传递一个已知类型的结构(所以你可以安全地将其强制转换),并在其中存储文件指针或字符串,以及一个枚举字段,让你知道哪两个是有效的一个。