我目前正在编写一个代码,我想使用它从具有大量数据字段的对象中获取数据。我的代码是这样的:
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*(字符串)。
除了手动查找每个函数的所有数据字段,按类型手动过滤它们并使get函数具有不同的返回类型之外,还有其他方法吗?
更新:
指定我想要达到的目标:
我知道它的类型,但它因情况而异。是否有一种解决方案,我可以使用从类传递类型到函数?
例如:
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)
}
(...)
};
您可以将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
时知道字段的类型,我不确定这是您的情况。考虑一下这个问题:如果你不知道应该是什么类型,你怎么能期望编译器能够推断它呢?
下面一行语法错误。
auto n_tracks = (auto)(*ptr);
编译器无法在编译时推断出ptr
的底层类型是什么。因为这个问题必须在编译时解决,所以您的方法不是一个可行的解决方案。你必须想出一个不同的策略来满足你的程序的需要。
你可以通过延续传递样式来解决这个问题。
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{} );
这将调用some_operation
的operator()
,类型为wbc
。
你可以做一些魔术使语法看起来像:
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
之类的东西将问题分成两个部分,它将"获取数据"与"处理每种类型的数据"组件很好地分开。
我认为Anthony vall
假设我们已经实现了这个特性,并且:1)如果我们调用函数get("wbc"),它返回int;2)如果我们调用函数get("delay"),它返回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
}
编译器需要把所有的信息都准备好并编译,这样它才能把所有的例程(或ASM)提供给CPU。
你可以想到模板
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
基本无用。如果需要限制对这些对象的访问,请使用代理对象和/或friend
。
解决方案很简单,只需调用get函数,然后根据传递的类型执行不同的操作:
的例子:
void* ptr = ... -> get( "ntracks" );
if( my_object -> interpret_as == "int" )
{
callsomefunc( (int*)ptr );
}
...
这段代码现在足够聪明,可以根据从配置文件中读取的类型做不同的事情。