2015-10-09 3 views
0

Я работаю над кодом, который я хочу использовать для извлечения данных из объектов с большим количеством полей данных. Мой код выглядит следующим образом:Есть ли способ автоматически указывать указатели void?

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

Это, однако, дает мне сообщение об ошибке ... Is есть способ добиться того, чего я хочу?

У меня действительно большие структуры с полями в следующих типах: int, double, int * (array), double * (array), char * (string).

Есть ли другой способ, чем вручную найти все поля данных для каждой функции, отфильтровывать их вручную по типам и получать функции с различными типами возврата?

Update:

Чтобы указать, что я хочу добиться:

Я знаю, что тип, но она меняется от случая к случаю. Есть ли решение, которое я могу использовать для передачи типа из класса в функцию?

Например:

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

У вас есть указатель на пустоту, так как компилятор знает что-либо о базовом типе, на который указывает? – Sean

+0

Вы всегда можете 'reinterpret_cast (...)' все в вашей функции. Я не уверен, что поможет строка 'auto n_tracks = (auto) (* ptr);', хотя; Я думаю, вам, возможно, придется сделать еще один «reinterpret_cast» обратно к соответствующему типу. –

+0

Имя поля говорит вам, что делать с полем, поэтому оно имеет больше информации, чем тип поля. Вместо функции 'get' я предлагаю функцию' do', которая будет принимать имя поля, и от этого берет значение, а также делать то, что он должен делать. – Dialecticus

ответ

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() из some_operation с типом 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, который отделяет «получить данные» от «процесса каждого типа данных» компонентов красиво.

1

В строке ниже синтаксически неправильно.

auto n_tracks = (auto)(*ptr); 

Там нет никакого способа для компилятора вывести, что основной тип ptr может быть во время компиляции. Поскольку это необходимо решить во время компиляции, ваш подход не является жизнеспособным решением. Вам придется придумать другую стратегию для удовлетворения потребностей вашей программы.

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, который я не уверен, что это ваш случай. Подумайте об этом, хотя: если вы не знаете, какой тип должен быть, как вы можете ожидать, что ваш компилятор сможет его вывести?

+0

Это, вероятно, так же хорошо, как и для OP. Вы также можете переместить 'reinterpret_cast ' в логику функции 'event_field-> get' и сделать его шаблоном функции. – dasblinkenlight

+0

Я обновил вопрос. –

+0

@AdamHunyadi Вы не можете действительно определять такие типы во время выполнения (запрет [RTTI] (https://en.wikipedia.org/wiki/Run-time_type_information)), и обычно это подчеркивает недостаток вашего дизайна, когда вы думаете, что это нужно сделать. –

0

Я думаю, что результат от Энтони Валле-Дюбуа - лучший ответ. Причина такова:

Предположим, что у нас есть функция, и: 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 
} 

Compiler нужна вся информация на месте и компиляции, так что она может обеспечить все процедуры (или 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 *****? 
} 

Так что это не возможно, так как вы должны необходимо определить и жёстко типа данных, где некоторые

0

Не делай этого. Это вредно и руины типа безопасности; болтающиеся указатели тоже не лучше.

Просто сделайте свои переменные public: способ, которым вы подвергаете их, делает private в основном бесполезным. Если вам необходимо ограничить доступ к ним, используйте прокси-объект и/или friend.

0

Решение было так просто, как вызов функции GET, а затем делать разные вещи в зависимости от пропускаемого типа:

Пример:

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

Этот код теперь достаточно умен, чтобы делать разные вещи, основанные на типы, считанные из файла конфигурации.

Смежные вопросы