在指向成员的指针之间转换
Converting among pointers-to-member
我知道您不能将指向成员的指针转换为指向非成员的指针(例如,void*
),但是您可以在指向成员的指针之间进行转换吗? class?例如:对于某些 class C
和类型 T
和 U
,您可以将 T C::*
转换为 U C::*
吗?
我希望能够将字符串名称映射到某些 class 的指向成员的指针。例如,给定:
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;
}
并打印我设置的值。但这合法吗?
(我想做这样的事情的原因是将从配置文件读取的参数名称和值映射到结构成员。)
for some class C and types T and U, can you convert a T C::* to a
U C::*?
简短的回答是肯定的。
当然是长答案。任何类型的数据指针都只是给你一个结构中实际数据的偏移量。类型信息未在指针中编码 - 数据类型在实际指针值之外。
不用说了,你的代码有点毛病。
只要在使用pointer-to-member之前将类型转换回原来的类型就没有问题。
来自 http://en.cppreference.com/w/cpp/language/reinterpret_cast reinterpret_cast 的描述:
.... It is purely a compiler directive which instructs the compiler to treat the sequence of bits (object representation) of expression as if it had the type new_type.
Only the following conversions can be done....
1) An expression of integral, enumeration, pointer, or pointer-to-member type can be converted to its own type. The resulting value is the same as the value of expression.
因此,将字符串类型的 pointer-to-member 转换为 OtherType 类型的 pointer-to-member,然后在稍后将 OtherType 类型的相同 pointer-to-member 转换回 pointer-to-member类型字符串非常好,不会改变 pointer-to-member.
的原始值
是的,这是合法的。在 reinterpret_cast
的描述中,语言规范说
A prvalue of type “pointer to member of X of type T1” can be explicitly converted to a prvalue of a different type “pointer to member of Y of type T2” if T1 and T2 are both function types or both object types. ... The
result of this conversion is unspecified, except [converting a pointer-to-member to another pointer-to-member and back gives the original pointer to member value].
所以它是允许的,但可能会或可能不会按照您的预期进行。
我知道您不能将指向成员的指针转换为指向非成员的指针(例如,void*
),但是您可以在指向成员的指针之间进行转换吗? class?例如:对于某些 class C
和类型 T
和 U
,您可以将 T C::*
转换为 U C::*
吗?
我希望能够将字符串名称映射到某些 class 的指向成员的指针。例如,给定:
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;
}
并打印我设置的值。但这合法吗?
(我想做这样的事情的原因是将从配置文件读取的参数名称和值映射到结构成员。)
for some class C and types T and U, can you convert a T C::* to a U C::*?
简短的回答是肯定的。
当然是长答案。任何类型的数据指针都只是给你一个结构中实际数据的偏移量。类型信息未在指针中编码 - 数据类型在实际指针值之外。
不用说了,你的代码有点毛病。
只要在使用pointer-to-member之前将类型转换回原来的类型就没有问题。
来自 http://en.cppreference.com/w/cpp/language/reinterpret_cast reinterpret_cast 的描述:
.... It is purely a compiler directive which instructs the compiler to treat the sequence of bits (object representation) of expression as if it had the type new_type.
Only the following conversions can be done....
1) An expression of integral, enumeration, pointer, or pointer-to-member type can be converted to its own type. The resulting value is the same as the value of expression.
因此,将字符串类型的 pointer-to-member 转换为 OtherType 类型的 pointer-to-member,然后在稍后将 OtherType 类型的相同 pointer-to-member 转换回 pointer-to-member类型字符串非常好,不会改变 pointer-to-member.
的原始值是的,这是合法的。在 reinterpret_cast
的描述中,语言规范说
A prvalue of type “pointer to member of X of type T1” can be explicitly converted to a prvalue of a different type “pointer to member of Y of type T2” if T1 and T2 are both function types or both object types. ... The result of this conversion is unspecified, except [converting a pointer-to-member to another pointer-to-member and back gives the original pointer to member value].
所以它是允许的,但可能会或可能不会按照您的预期进行。