Я знаю, что вы не можете преобразовать указатель-член к указателю на не-член (например, void*
), но можете ли вы преобразовать между указателями на член для тот же класс? Например: для некоторого класса C
и типы T
и U
, можете ли вы преобразовать T C::*
в U C::*
?Преобразование между указателями к объекту
Я хочу, чтобы иметь возможность отображать имена строк в указатели на элемент для некоторого класса. Например, учитывая:
template<class ClassType>
struct mbr_map_traits {
typedef std::string mbr_name_type;
typedef void* ClassType::*any_mbr_ptr;
typedef std::map<mbr_name_type,any_mbr_ptr> map_type;
};
/**
* A %mbr_map is used to map a string to an arbitrary pointer-to-member of some class.
* @tparam ClassType The class whose members to map to.
*/
template<class ClassType>
struct mbr_map : mbr_map_traits<ClassType>::map_type {
typedef typename mbr_map_traits<ClassType>::mbr_name_type mbr_name_type;
/**
* Initalizes an entry in the map so as to mape \a name to a pointer-to-member.
* @param name The name to map.
* @param p The pointer-to-member to map to.
*/
template<typename MemberType>
void mbr_init(mbr_name_type const &name, MemberType ClassType::*p) {
typedef typename mbr_map_traits<ClassType>::any_mbr_ptr any_mbr_ptr;
(*this)[ name ] = reinterpret_cast<any_mbr_ptr>(p); // IS THIS OK?
}
/**
* Sets the value of a class member by name.
* @param c The class whose member to set.
* @param name The name of the class member to set.
* @param value The value to set the member to.
* @return true only if \a name exists in the map.
*/
template<typename MemberType>
bool mbr_set(ClassType &c, mbr_name_type const &name, MemberType const &value) {
typedef typename mbr_map<ClassType>::const_iterator const_iterator;
const_iterator const found = this->find(name);
if (found != this->end()) {
typedef MemberType ClassType::*mbr_ptr;
c.*reinterpret_cast<mbr_ptr>(found->second) = value; // IS THIS OK?
return true;
}
return false;
}
};
и некоторые разовый инициализации:
struct S {
std::string s;
int i;
bool b;
};
void mbr_map_init(mbr_map<S> *m) {
m->mbr_init("string_mbr", &S::s);
m->mbr_init("int_mbr", &S::i);
m->mbr_init("bool_mbr", &S::b);
}
Я могу это сделать:
using namespace std;
int main() {
mbr_map<S> m;
mbr_map_init(&m);
S s;
m.mbr_set(s, "string_mbr", string("hello"));
m.mbr_set(s, "int_mbr", 42);
m.mbr_set(s, "bool_mbr", true);
cout << s.s << endl;
cout << s.i << endl;
cout << s.b << endl;
return 0;
}
и печатает значения I набора. Но есть ли это legal?
(Поэтому я хочу сделать что-то вроде этого является отображение параметров имен и значений, считанных из файла конфигурации в структуре пользователей.)
Итак, как бы вы это сделали? –
Я бы не стал доверять случайным пользовательским вводам для указания типа. Вы можете форматировать имена с помощью препроцессора и использовать его для связывания имен с типами и полями, которые выполняются во время компиляции. Во время выполнения у вас есть только специализированный синтаксический анализатор, связанный с именем. Никакой реинтерпрет не бросается нигде, и никакого типа угадывания mbr_set. Но если вы хотите сохранить свою карту, по крайней мере, проверьте, что тип тот же. Например, вы можете использовать boost :: any для этого или std :: type_info – user3427419
Мой код, как написано, жестко кодирует имена и типы. Вход пользователя поступает только из файлов conf, которые по определению должны настраиваться пользователем. –