有没有办法自动类型转换 void 指针?
Is there a way to automatically typecast void pointers?
我目前正在编写一个代码,我想用它从具有大量数据字段的对象中获取数据。我的代码如下所示:
void* get( std :: string field_name )
{
(...)
if( field_name == "wbc" ) { return &(this -> wbc); };
if( field_name == "delay" ) { return &(this -> delay); };
if( field_name == "ntracks" ) { return &(this -> ntracks); };
if( field_name == "ntrackFPix" ) { return &(this -> ntrackFPix); };
if( field_name == "ntrackBPix" ) { return &(this -> ntrackBPix); };
if( field_name == "ntrackFPixvalid" ) { return &(this -> ntrackFPixvalid); };
if( field_name == "ntrackBPixvalid" ) { return &(this -> ntrackBPixvalid); };
(...)
std :: cerr << "Error: EventData.get() is unable to find the field: "
<< field_name << ". " << std :: endl;
exit( -1 );
return NULL;
}
这就是我调用 get() 函数的方式 (C++11):
void* ptr = this -> event_field -> get( "ntracks" );
auto n_tracks = (auto)(*ptr);
然而,这给了我一条错误信息...
有没有办法实现我想要的?
我有非常大的结构,其中包含以下类型的字段:int、double、int*(数组)、double*(数组)、char*(字符串)。
除了手动查找每个函数的所有数据字段,然后按类型手动筛选并制作具有不同 return 类型的 get 函数外,还有其他方法吗?
更新:
指定我要实现的目标:
我知道类型,但因情况而异。有没有我可以用来将类型从 class 传递给函数的解决方案?
例如:
Class A
{
std :: vector<std :: string> typenames;
std :: vector<std :: string> identifiers;
};
Class B
{
(...)
{
(I want to get the given field of given type (specified in A) from a massive object with lots of fields( and I don't know before runtime which fields I will need)
}
(...)
};
下面这行语法不正确。
auto n_tracks = (auto)(*ptr);
编译器无法在编译时推断出ptr
的基础类型。由于这必须在编译时解决,因此您的方法不是可行的解决方案。您必须想出不同的策略来满足程序的需要。
您可以将 get
函数包装在函数模板中,将值转换为模板参数类型。它会减少冗长,尽管我怀疑您的程序设计中存在更大的问题使得这些转换成为必要。
template<T>
T* get(std::string field) {
return reinterpret_cast<T*>(this->event_field->get(field));
}
// Used as such
double* ptr = this->get<double>("field_name");
请注意,这要求您在调用 get
时知道字段的类型,我不确定您是否属于这种情况。不过请考虑一下:如果您不知道该类型应该是什么,您怎么能期望您的编译器能够推断出它呢?
我认为 Anthony Vallée-Dubois 的结果是最好的答案。原因如下:
假设我们已经实现了该功能,并且:
1) 如果我们调用函数get("wbc"),它是return int;
2) 如果我们调用函数get("delay"),它return std::string;
void valueUser( const std::string& str )
{
***** value = get(str); //What we can input to the place *****??
value ++; // can it be possible for all return type
if ( value.at(0) == 'M' ); // can it be possible for all return type
}
编译器需要所有信息就位并进行编译,以便它可以向CPU.
提供所有例程(或ASM)
你可能会想到模板
template<>
void valueUser<int>( const std::string& str )
{
int value = get(str); //how we can grantee the return is int?
value ++;
}
template<>
void valueUser<std::string>( const std::string& str )
{
std::string value = get(str); //how we can grantee the return is std::string?
if ( value.at(0) == 'M' );
}
int main()
{
valueUser<*****>(""); // what is *****?
}
所以这是不可能的,因为您必须在某些地方定义和硬编码数据类型
不要那样做。它是有害的,会破坏类型的安全;悬挂指针也没什么好。
只需让您的变量 public
:您公开它们的方式使 private
基本上毫无用处。如果您需要限制对这些的访问,请使用代理对象 and/or friend
.
你可以用continuation passing style来解决这个问题。
template<class F>
auto get( std :: string field_name, F f )
-> typename std::result_of< F(int&) >::type // assuming at least one arg is an int
{
(...)
if( field_name == "wbc" ) { return f(wbc); };
if( field_name == "delay" ) { return f(delay); };
if( field_name == "ntracks" ) { return f(ntracks); };
if( field_name == "ntrackFPix" ) { return f(ntracFPix); };
if( field_name == "ntrackBPix" ) { return f(ntrackBPix); };
if( field_name == "ntrackFPixvalid" ) { return f(ntrackFPixvalid); };
if( field_name == "ntrackBPixvalid" ) { return f(ntrackBPixvalid); };
(...)
std :: cerr << "Error: EventData.get() is unable to find the field: "
<< field_name << ". " << std :: endl;
exit( -1 ); // no more need for a return after an exit(-1);
}
使用看起来像:
struct some_operation {
template<class T>
void operator()(T& t){
std::cout << t << '\n';
}
};
foo.get( "wbc", some_operation{} );
这将调用类型为 wbc
的 some_operation
的 operator()
。
您可以施展魔法,使语法看起来像这样:
foo.get( "wbc" )
->* some_operation{}
或者在 C++14 中:
foo.get( "wbc" )
->*[&](auto&& val){
std::cout << val << '\n';
};
我们使用 operator->*
进行一些链接。但这越来越花哨了。
请注意,您应该采取 F&&
并执行上面的 std::forward<F>(f)(wbc);
,但这并不重要,而且会混淆问题。
您也可以使用 boost::variant
之类的方法将问题分成两部分,它可以很好地将 "get the data" 与 "process each type of the data" 部分分开。
解决方法很简单,就是调用 get 函数,然后根据传递的类型做不同的事情:
示例:
void* ptr = ... -> get( "ntracks" );
if( my_object -> interpret_as == "int" )
{
callsomefunc( (int*)ptr );
}
...
此代码现在足够智能,可以根据从配置文件中读取的类型执行不同的操作。
我目前正在编写一个代码,我想用它从具有大量数据字段的对象中获取数据。我的代码如下所示:
void* get( std :: string field_name )
{
(...)
if( field_name == "wbc" ) { return &(this -> wbc); };
if( field_name == "delay" ) { return &(this -> delay); };
if( field_name == "ntracks" ) { return &(this -> ntracks); };
if( field_name == "ntrackFPix" ) { return &(this -> ntrackFPix); };
if( field_name == "ntrackBPix" ) { return &(this -> ntrackBPix); };
if( field_name == "ntrackFPixvalid" ) { return &(this -> ntrackFPixvalid); };
if( field_name == "ntrackBPixvalid" ) { return &(this -> ntrackBPixvalid); };
(...)
std :: cerr << "Error: EventData.get() is unable to find the field: "
<< field_name << ". " << std :: endl;
exit( -1 );
return NULL;
}
这就是我调用 get() 函数的方式 (C++11):
void* ptr = this -> event_field -> get( "ntracks" );
auto n_tracks = (auto)(*ptr);
然而,这给了我一条错误信息... 有没有办法实现我想要的?
我有非常大的结构,其中包含以下类型的字段:int、double、int*(数组)、double*(数组)、char*(字符串)。
除了手动查找每个函数的所有数据字段,然后按类型手动筛选并制作具有不同 return 类型的 get 函数外,还有其他方法吗?
更新:
指定我要实现的目标:
我知道类型,但因情况而异。有没有我可以用来将类型从 class 传递给函数的解决方案?
例如:
Class A
{
std :: vector<std :: string> typenames;
std :: vector<std :: string> identifiers;
};
Class B
{
(...)
{
(I want to get the given field of given type (specified in A) from a massive object with lots of fields( and I don't know before runtime which fields I will need)
}
(...)
};
下面这行语法不正确。
auto n_tracks = (auto)(*ptr);
编译器无法在编译时推断出ptr
的基础类型。由于这必须在编译时解决,因此您的方法不是可行的解决方案。您必须想出不同的策略来满足程序的需要。
您可以将 get
函数包装在函数模板中,将值转换为模板参数类型。它会减少冗长,尽管我怀疑您的程序设计中存在更大的问题使得这些转换成为必要。
template<T>
T* get(std::string field) {
return reinterpret_cast<T*>(this->event_field->get(field));
}
// Used as such
double* ptr = this->get<double>("field_name");
请注意,这要求您在调用 get
时知道字段的类型,我不确定您是否属于这种情况。不过请考虑一下:如果您不知道该类型应该是什么,您怎么能期望您的编译器能够推断出它呢?
我认为 Anthony Vallée-Dubois 的结果是最好的答案。原因如下:
假设我们已经实现了该功能,并且: 1) 如果我们调用函数get("wbc"),它是return int; 2) 如果我们调用函数get("delay"),它return std::string;
void valueUser( const std::string& str )
{
***** value = get(str); //What we can input to the place *****??
value ++; // can it be possible for all return type
if ( value.at(0) == 'M' ); // can it be possible for all return type
}
编译器需要所有信息就位并进行编译,以便它可以向CPU.
提供所有例程(或ASM)你可能会想到模板
template<>
void valueUser<int>( const std::string& str )
{
int value = get(str); //how we can grantee the return is int?
value ++;
}
template<>
void valueUser<std::string>( const std::string& str )
{
std::string value = get(str); //how we can grantee the return is std::string?
if ( value.at(0) == 'M' );
}
int main()
{
valueUser<*****>(""); // what is *****?
}
所以这是不可能的,因为您必须在某些地方定义和硬编码数据类型
不要那样做。它是有害的,会破坏类型的安全;悬挂指针也没什么好。
只需让您的变量 public
:您公开它们的方式使 private
基本上毫无用处。如果您需要限制对这些的访问,请使用代理对象 and/or friend
.
你可以用continuation passing style来解决这个问题。
template<class F>
auto get( std :: string field_name, F f )
-> typename std::result_of< F(int&) >::type // assuming at least one arg is an int
{
(...)
if( field_name == "wbc" ) { return f(wbc); };
if( field_name == "delay" ) { return f(delay); };
if( field_name == "ntracks" ) { return f(ntracks); };
if( field_name == "ntrackFPix" ) { return f(ntracFPix); };
if( field_name == "ntrackBPix" ) { return f(ntrackBPix); };
if( field_name == "ntrackFPixvalid" ) { return f(ntrackFPixvalid); };
if( field_name == "ntrackBPixvalid" ) { return f(ntrackBPixvalid); };
(...)
std :: cerr << "Error: EventData.get() is unable to find the field: "
<< field_name << ". " << std :: endl;
exit( -1 ); // no more need for a return after an exit(-1);
}
使用看起来像:
struct some_operation {
template<class T>
void operator()(T& t){
std::cout << t << '\n';
}
};
foo.get( "wbc", some_operation{} );
这将调用类型为 wbc
的 some_operation
的 operator()
。
您可以施展魔法,使语法看起来像这样:
foo.get( "wbc" )
->* some_operation{}
或者在 C++14 中:
foo.get( "wbc" )
->*[&](auto&& val){
std::cout << val << '\n';
};
我们使用 operator->*
进行一些链接。但这越来越花哨了。
请注意,您应该采取 F&&
并执行上面的 std::forward<F>(f)(wbc);
,但这并不重要,而且会混淆问题。
您也可以使用 boost::variant
之类的方法将问题分成两部分,它可以很好地将 "get the data" 与 "process each type of the data" 部分分开。
解决方法很简单,就是调用 get 函数,然后根据传递的类型做不同的事情:
示例:
void* ptr = ... -> get( "ntracks" );
if( my_object -> interpret_as == "int" )
{
callsomefunc( (int*)ptr );
}
...
此代码现在足够智能,可以根据从配置文件中读取的类型执行不同的操作。