我有一个有3个参数的功能。第三个参数的数据类型为void*
,有两种类型的数据可以通过std::string
或FILE*
传递。
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*
的数据类型?
答案 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 *
后,类型信息将丢失。这里通常的方法是传递一个已知类型的结构(所以你可以安全地将其强制转换),并在其中存储文件指针或字符串,以及一个枚举字段,让你知道哪两个是有效的一个。