指针转换为成员

时间:2016-01-06 03:40:09

标签: c++ casting pointer-to-member

我知道你不能将指向成员的指针转换为指向非成员的指针(例如,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;
}

并打印我设置的值。但这是合法吗?

(我想做这样的事情的原因是将从配置文件中读取的参数名称和值映射到结构成员。)

3 个答案:

答案 0 :(得分:1)

只要在使用指向成员的指针之前将转换回原始类型,就没有问题。

来自http://en.cppreference.com/w/cpp/language/reinterpret_cast reinterpret_cast的描述:

  

....它纯粹是一个编译器指令,它指示编译器将表达式的位序列(对象表示)视为具有new_type类型。

     

只能进行以下转换....

     

1)可以将整数,枚举,指针或指向成员指针类型的表达式转换为自己的类型。 结果值与表达式的值相同。

因此,将类型为string的指针成员转换为类型为OtherType的指针成员,然后在稍后的位置将类型为OtherType的指针转换为成员返回指向成员类型的成员非常好,不会改变指向成员的指针的原始值。

答案 1 :(得分:0)

  

对于某些C类和T和U类型,您可以将 T C :: * 转换为    U C :: *

简短回答是肯定的。

当然,答案很长。无论何种类型的数据指针,都只能为结构中的实际数据提供偏移量。类型信息未在指针中编码 - 数据类型在实际指针值的外部。

毋庸置疑,您的代码有点多毛

答案 2 :(得分:0)

是的,这是合法的。在reinterpret_cast的说明中,语言规范说明了

  

如果T1和T2都是函数类型或两种对象类型,则可以将类型“指向类型T1的X成员的指针”类型的prvalue显式转换为不同类型的prvalue“指向类型为T2的Y的成员的指针” 。 ......   这个转换的结果是未指定的,除了[将指针指向成员转换为另一个指向成员的指针并返回将原始指针指向成员值]。

所以这是允许的,但可能会也可能不会达到预期目的。