boost::any and const pointers
I have a
map
On Wed, Dec 2, 2009 at 10:55 AM, James C. Sutherland
int main() { Properties p; int i=1; set(p,"int",i); set(p,"int*",&i);
int* j = get
(p,"int*"); // I don't want this to compile const int* k = get (p,"int*"); // I want this to compile fine. } Currently this whole code compiles without trouble, but I don't want to allow a non-const pointer to be extracted. Any ideas of how to accomplish this?
Thanks not possible AFAIK. The first compiles alright, but will fail at runtime because the boost::any was constructed using a const int*. By design all extractions are checked at runtime only, and the typeid()/std::type_info of what you put in and what you try to get it as must be the same. Given your code, you can't even do get<int>(p, "int"), because a const int was put in, not an int (see your set() impl), and typeid(int) != typeid(const int). --DD
On Dec 2, 2009, at 11:24 AM, Dominique Devienne wrote:
On Wed, Dec 2, 2009 at 10:55 AM, James C. Sutherland
wrote: int main() { Properties p; int i=1; set(p,"int",i); set(p,"int*",&i);
int* j = get
(p,"int*"); // I don't want this to compile const int* k = get (p,"int*"); // I want this to compile fine. } Currently this whole code compiles without trouble, but I don't want to allow a non-const pointer to be extracted. Any ideas of how to accomplish this?
Thanks not possible AFAIK. The first compiles alright, but will fail at runtime because the boost::any was constructed using a const int*. By design all extractions are checked at runtime only, and the typeid()/std::type_info of what you put in and what you try to get it as must be the same. Given your code, you can't even do get<int>(p, "int"), because a const int was put in, not an int (see your set() impl), and typeid(int) != typeid(const int). --DD
Actually, this runs just fine (at least on my mac running g++ 4.2.1). Also, the following compiles and runs fine: int m = get<int>(p,"int"); This is because you cannot force const semantics on a copy. I came up with a way to get const references out (using boost::ref), but can't get const pointers guaranteed. I fear that you are right about this not being possible.
On Wed, Dec 2, 2009 at 1:03 PM, James C. Sutherland
On Dec 2, 2009, at 11:24 AM, Dominique Devienne wrote:
On Wed, Dec 2, 2009 at 10:55 AM, James C. Sutherland Actually, this runs just fine (at least on my mac running g++ 4.2.1).
Ah, sorry, you're right of course, since with const T t, when passed an int*, the const is applied to the pointer and not the int, so it's only a int*const instead of a const int* (or int const *). Given that typeid(int *const) == typeid(int*), that why you can get it as a "int*" later on. This time I double-checked by printing the types in your set() method and verifying that typeid(int*) == typeid(int*const). C:\C++>any_cast.exe typeid(T) = int (.H) typeid(t) = int (.H) typeid(T) = int * (.PAH) typeid(t) = int * (.PAH) C:\C++>typeid_test.exe ... typeid(int*) = int * (.PAH) typeid(const int*) = int const * (.PBH) typeid(int*const) = int * (.PAH) typeid(const int*const) = int const * (.PBH) ...
Also, the following compiles and runs fine: int m = get<int>(p,"int"); This is because you cannot force const semantics on a copy.
You're right again. Should have run my typeid tests again to refresh my memory before I answered your post :) C:\C++>g++ -O2 typeid_test.cpp C:\C++>a.exe typeid(int) = int (i) typeid(const int) = int (i) .... C:\C++>cl /Od /EHsc /nologo typeid_test.cpp typeid_test.cpp C:\C++>typeid_test.exe typeid(int) = int (.H) typeid(const int) = int (.H) ...
I came up with a way to get const references out (using boost::ref), but can't get const pointers guaranteed. I fear that you are right about this not being possible.
As you mention, can't force const on values, and references are just like values as far as typeid() is concerned: typeid(Base) = class Base (.?AVBase@@) typeid(Base&) = class Base (.?AVBase@@) typeid(const Base) = class Base (.?AVBase@@) typeid(const Base&) = class Base (.?AVBase@@) OTOH, with pointers: typeid(mutab_pt) = class Point3d (.?AVPoint3d@@) typeid(const_pt) = class Point3d (.?AVPoint3d@@) typeid(ptr_mutab_pt) = class Point3d * (.PAVPoint3d@@) typeid(ptr_const_pt) = class Point3d const * (.PBVPoint3d@@) with Point3d mutab_pt(2,3,4); const Point3d const_pt(3,4,5); Point3d* ptr_mutab_pt = &mutab_pt; const Point3d* ptr_const_pt = &const_pt; Bottom line is, if typeid() of what you put in doesn't match typeid() of what you're trying to get it as, it will fail, and a pointer to T will not be any_cast'able as a pointer to const T, or vice-versa (you can't even get the T* as a T const*, despite the valid implicit conversion, you must first get it as a T*, and then rely on the normal implicit pointer conversion). --DD
AMDG James C. Sutherland wrote:
I have a map
that I would like to control access to so that if a pointer is put in the map, only a const pointer can be extracted. The following simple code illustrates the situation. //-------------------- <snip> -------------------------- typedef std::mapstd::string,boost::any Properties;
template<typename T> void set( Properties& p, const std::string name, const T t ) { p[name] = t; }
template<typename T> const T get( const Properties& p, const std::string name ) { const Properties::const_iterator iprop=p.find(name); try{ const T t = boost::any_cast<const T>(iprop->second); return t; } catch(const boost::bad_any_cast &){ throw std::runtime_error("bad cast"); } }
int main() { Properties p; int i=1; set(p,"int",i); set(p,"int*",&i);
int* j = get
(p,"int*"); // I don't want this to compile const int* k = get (p,"int*"); // I want this to compile fine. } //-------------------- </snip> ------------------------- Currently this whole code compiles without trouble, but I don't want to allow a non-const pointer to be extracted. Any ideas of how to accomplish this?
template<typename T> const typename boost::remove_pointer<T>::type* get(const Properties& p, const std::string& name); In Christ, Steven Watanabe
On Dec 2, 2009, at 2:19 PM, Steven Watanabe wrote:
AMDG
James C. Sutherland wrote:
I have a map
that I would like to control access to so that if a pointer is put in the map, only a const pointer can be extracted. The following simple code illustrates the situation. //-------------------- <snip> -------------------------- typedef std::mapstd::string,boost::any Properties;
template<typename T> void set( Properties& p, const std::string name, const T t ) { p[name] = t; }
template<typename T> const T get( const Properties& p, const std::string name ) { const Properties::const_iterator iprop=p.find(name); try{ const T t = boost::any_cast<const T>(iprop->second); return t; } catch(const boost::bad_any_cast &){ throw std::runtime_error("bad cast"); } }
int main() { Properties p; int i=1; set(p,"int",i); set(p,"int*",&i);
int* j = get
(p,"int*"); // I don't want this to compile const int* k = get (p,"int*"); // I want this to compile fine. } //-------------------- </snip> ------------------------- Currently this whole code compiles without trouble, but I don't want to allow a non-const pointer to be extracted. Any ideas of how to accomplish this?
template<typename T> const typename boost::remove_pointer<T>::type* get(const Properties& p, const std::string& name);
In Christ, Steven Watanabe
Thank you! That works great for pointers, but now not for POD, e.g., const int m = get<int>(p,"int"); Any ideas of how to get this to work with POD and pointers?
On Wed, Dec 2, 2009 at 3:29 PM, James C. Sutherland < James.Sutherland@utah.edu> wrote:
Thank you! That works great for pointers, but now not for POD, e.g., const int m = get<int>(p,"int"); Any ideas of how to get this to work with POD and pointers?
Why can't you use boost::enable_if and only enable the get<> template if the
argument is const? This imposes the restriction that you actually invoke
the get<> template as follows:
const int m = get<const int>(p, "int");
const int* m2 = get
AMDG James C. Sutherland wrote:
Thank you! That works great for pointers, but now not for POD, e.g., const int m = get<int>(p,"int"); Any ideas of how to get this to work with POD and pointers?
typename boost::mpl::eval_if
::type
In Christ, Steven Watanabe
On Dec 2, 2009, at 3:03 PM, Steven Watanabe wrote:
AMDG
James C. Sutherland wrote:
Thank you! That works great for pointers, but now not for POD, e.g., const int m = get<int>(p,"int"); Any ideas of how to get this to work with POD and pointers?
typename boost::mpl::eval_if
::type , boost::add_const<T> ::type
In Christ, Steven Watanabe
You can work magic! I suppose that I need to dig into MPL and the type_traits libraries in boost. template< typename T > typename boost::mpl::eval_if< boost::is_pointer<T>, boost::add_pointer< typename boost::add_const< typename boost::remove_pointer<T>::type >::type >, boost::add_const<T> >::type get( const Properties& p, const std::string name ) { ... } that did the job.
participants (4)
-
Dominique Devienne
-
James C. Sutherland
-
Steven Watanabe
-
Zachary Turner