Могу ли я безопасно привести указатель на член 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;
}
}
};
Если вы хотите убить const
, затем const_cast
является единственным жизнеспособным инструментом для работы.