Могу ли я безопасно привести указатель на член const того же типа, но не const?

... хотя указатели на функции-члены являются странными животными?

Я кодирую библиотеку для привязки классов C++ к Lua. Мне приходится иметь дело с стиранием типов, вызванным помещением объектов определенных типов в стек Lua (и, следовательно, приведением их к void*). По этой причине, но также во избежание чрезмерного распространения различных шаблонов для разных типов данных (неконстантные и константные объекты, неконстантные и константные члены, а в будущем все удваивается для энергозависимых и энергонезависимых....), мне удается постоянство объекта, связанного с Lua во время выполнения, просто установив определенный флаг.

Теперь я имею дело с указателями на функцию-член. Следуя моему замыслу, я был бы рад, если бы мог безопасно привести указатель на функцию-член const к неконстантной, затем повторно использовать тот же шаблон для не-const и работать с константой во время выполнения с помощью вышеупомянутого флага.

Но есть еще один намек, который заставляет меня задуматься, действительно ли это возможно. Рассмотрим код ниже:

#include <iostream>
#include <typeinfo>
using namespace std;

struct A{
    const int a;
    int b;
};

template<typename T> struct tmpl;

template<typename Class, typename FT> struct tmpl<FT(Class::*)>{
    static void f(){
        cout<<"non const"<<endl;
    }
};

//Try commenting this out, code compiles, both A::a and A::b instantiate the first template
template<typename Class, typename FT> struct tmpl<const FT(Class::*)>{
    static void f(){
        cout<<"const"<<endl;
    }
};

int main(){
    cout<<typeid(&A::a).name()<<endl;   //prints "M1AKi"
    tmpl<decltype(&A::a)>::f();         //prints "const"
    cout<<typeid(&A::b).name()<<endl;   //prints "M1Ai"
    tmpl<decltype(&A::b)>::f();         //prints "non const"
    //Let's do what it seems that can be done implicitly (providing only one template specialization) in an explicit way
    int(A::*memb)=(int(A::*))&A::a;
    cout<<typeid(memb).name()<<endl;    //prints "M1Ai"
    tmpl<decltype(memb)>::f();          //prints "non const"
}

Похоже, что независимо от того, что эти животные могут даже изменить свой собственный размер, в определенных обстоятельствах вы можете безопасно бросить (или, по крайней мере, const_cast) их для других типов (если они имеют смысл).

Итак, мои рассуждения ужасно неправильны на одном из шагов, или я могу сделать это независимо от компилятора? Могу ли я так же играть с указателями на константные функции-члены?

1 ответ

Решение

В "неконстантной" специализации FT просто выводится, чтобы включить квалификатор const. Оно не исчезает, оно просто передается.

Попробуй это:

template<typename Class, typename FT> struct tmpl<FT(Class::*)>{
    static void f(){
        if ( std::is_const< FT >::value ) {
            cout<<"const as non const"<<endl;
        } else {
            cout<<"non const"<<endl;
        }
    }
};

http://ideone.com/g2Eie

Если вы хотите убить const, затем const_cast является единственным жизнеспособным инструментом для работы.

Другие вопросы по тегам