有没有办法自动类型化void指针?

时间:2015-10-09 15:42:12

标签: c++ c++11 casting return-value auto

我目前正在研究一种代码,我想用它来从具有大量数据字段的对象中获取数据。我的代码如下所示:

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 *(array),double *(array),char *(string)。

除了手动查找每个函数的所有数据字段,还是按类型手动过滤它们并使用不同的返回类型获取函数之外,还有其他方法吗?

更新

指定我想要达到的目标:

我知道这种类型,但因情况而异。有没有可以用来将类型从类传递给函数的解决方案?

例如:

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)
    }
    (...)
};

6 个答案:

答案 0 :(得分:2)

您可以将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时知道字段的类型,我不确定您的情况。但请考虑一下:如果您不知道该类型应该是什么,那么您如何期望编译器能够推断出它呢?

答案 1 :(得分:1)

以下行在语法上不正确。

auto n_tracks = (auto)(*ptr);

编译器无法在编译时推断出ptr的基础类型。由于必须在编译时解决,因此您的方法不是可行的解决方案。您必须提出不同的策略来满足您的计划需求。

答案 2 :(得分:0)

我认为AnthonyVallée-Dubois的结果是最好的答案。原因如下:

假设我们已实现该功能,并且: 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
}

编译器需要所有信息并进行编译,以便它可以为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 *****?
}

所以这是不可能的,因为你必须在某些地方定义和硬编码数据类型

答案 3 :(得分:0)

不要那样做。这是有害的,废墟式的安全;悬挂指针也没什么好处。

只需制作变量public:你暴露它们的方式使得private基本没用。如果您需要限制对这些访问权限,请使用代理对象和/或friend

答案 4 :(得分:0)

您可以使用延续传递样式解决此问题。

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{} );

这将调用类型为operator()的{​​{1}} some_operation

你可以做一些魔术来使语法看起来像:

wbc

或在C ++ 14中:

foo.get( "wbc" )
->* some_operation{}

我们使用foo.get( "wbc" ) ->*[&](auto&& val){ std::cout << val << '\n'; }; 进行链接。但这很有趣。

请注意,您应该使用operator->*并执行F&&以上,但这很少重要,这会使问题混乱。

您还可以使用std::forward<F>(f)(wbc);之类的内容将问题拆分为两位,这样可以分离&#34;获取数据&#34;来自&#34;处理每种类型的数据&#34;组件很好。

答案 5 :(得分:0)

解决方案就像调用get函数一样简单,然后根据传递的类型执行不同的操作:

示例:

void* ptr = ... -> get( "ntracks" );
if( my_object -> interpret_as == "int" )
{
     callsomefunc( (int*)ptr ); 
}
...

此代码现在足够智能,可以根据从配置文件中读取的类型执行不同的操作。