代码之家  ›  专栏  ›  技术社区  ›  Paul J. Lucas

在指向成员的指针之间转换

  •  0
  • Paul J. Lucas  · 技术社区  · 9 年前

    我知道您不能将指向成员的指针转换为指向非成员的指针(例如。, void* ),但能否在指向同一类的成员的指针之间进行转换?E、 例如:对于某些班级 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 回复  |  直到 9 年前
        1
  •  1
  •   4386427    9 年前

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

    从…起 http://en.cppreference.com/w/cpp/language/reinterpret_cast reinterpret_cast的描述:

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

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

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

    因此,将指向类型string成员的指针转换为指向类型OtherType成员的指针,然后在稍后将指向类型OherType成员的相同指针转换回指向类型strng成员的指针是非常好的,不会更改指向成员的指针的原始值。

        2
  •  0
  •   user3427419    9 年前

    对于某些C类、T类和U类,可以将 抄送:* 抄送::* ?

    简短的回答是肯定的。

    当然,答案很长。任何类型的数据指针都只会给你一个结构中实际数据的偏移量。类型信息未在指针中编码-数据类型位于实际指针值的外部。

    不用说,您的代码有点 多毛的 .

        3
  •  0
  •   1201ProgramAlarm    9 年前

    是的,这是合法的。在的描述中 reinterpret_cast ,语言规范说,

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

    因此,这是允许的,但可能会或可能不会达到你期望的效果。