Skip to main content
GameDev.net gamedev.net
🔒 Locked

Boost MPL help please

Started by Amnesty2 Mar 13, 2007 at 2:20 PM 8 replies 1.2k views
Original Post
Amnesty2
Amnesty2

typedef typename boost::mpl::if_
		<
		boost::is_class<Type>, 	
			typename Type::value_type,		
			Type	
		>::type value_type;


I need something similiar to this to work :) Sorry for the silly question, I havent used C++ or MPL in a very long time. Anyway the problem is that when Type is a class it works fine, but when Type isnt the compiler jokes on typename Type::value_type which is illegal (i.e int::value_type) Im sure there is this obvious answer but i haven been able to get it to work Im using VS 2K5
Julian90
Julian90
It wont work because the compiler has to instantiate both template arguments even if only one is used, have a look at boost::mpl::eval_if otherwise what you need is type traits and SFINAE (google them) something along these lines will work

struct sfinae{    typedef char one;    typedef struct { char c[2] } two;};template<typename T>struct has_value_type{private:    template<typename T>    struct wrap { };    template<typename T>    sfinae::one test(Wrap<typename T::value_type>*);    template<typename T>    sfinae::two test(...);public:    // if T has a value_type then test(0) will call the first    // version and return sfinae::one otherwise it will call     // the second version    enum { value = sizeof(test(0)) == sizeof(sfinae::one) };};template<typename T, bool HasValueType = has_value_type<T>::value>struct get_value_type;template<typename T>struct get_value_type<T, true>{    typedef typename T::value_type value_type;};template<typename T>struct get_value_type<T, false>{    typedef T value_type;}


of course instead of has_value_type which will cause it to use T for classes with no value_type you can use boost::is_class or boost::is_fundamental.
Amnesty2
Amnesty2
Sorry, can you give me an example of how to use eval_if in that example.
I kinda knew i needed eval_ifs lazyiness from distant memory of using MPL but simply subing in eval_if for if_ in the code i gave, the compiler chokes on the same error.

While I've got an example working right now of it properly switching types, I would rather not type up 4 structs everytime i need to type switch. Can i utilize the MPL framework to get this example working?
Julian90
Julian90
template<typename T>struct stuff{    // meta-function that returns T::value_type    template<typename Type>    struct use_value_type    {        typedef typename Type::value_type type;    };    // meta_function that returns T    template<typename Type>    struct use_type    {        typedef Type type;    };    typedef typename boost::mpl::eval_if    <        // if it is a class        boost::is_class<T>,        // boost will use return the ::type of this type        use_value_type<T>,        // otherwise it returns the ::type of this type        use_type<T>    >::type type;};
Amnesty2
Amnesty2
Thanks a lot. rating up.
Amnesty2
Amnesty2
Okay, i broke my code again. I diecided to use the right technique as shown by Julian90 if a class defines a specific type instead of just checking if its a class-type and asuming it defines value_type. And I diecided to go a head and do all the common types for standard containers just so its more complete.

Anyway,it worked great but then i tried changing the class around so it meets all the requirements for MPL meta function so i can use in MPL with ease. Before i got done with that, I hit a wall and I can't see what the problem is. It seems just so strange to me. I've been staring at for a few hours now.

Problem is explained in the comments near the end of the source block.

Oh, can someone tell me how to view my code after the preprocessor has made its substitutions? I hear of people doing it all the time but i never seen than option in any IDE i've used. Im using VS2005 right now.

#ifndef HPP_CONTAINER_TRAITS_03152007#define HPP_CONTAINER_TRAITS_03152007namespace tmp{namespace detail{struct sfinae_types{    typedef char one;    typedef struct { char c[2]; } two;};template <typename T> 	struct Wrap {};} // end namespace detail#define define_type_check(type_name) template<class T> struct has_##type_name { private: 	template<class T> static detail::sfinae_types::one test(detail::Wrap<typename T::type_name>*); 	template<class T> static detail::sfinae_types::two test(...); 	template<typename T, bool HasTypeName> 	struct get_type_name; 	template<typename T> 	struct get_type_name<T, true> 	{ 	    typedef typename T::type_name type; 	}; 	template<typename T> 	struct get_type_name<T, false> 	{ 	    typedef T type; 	}; public: 	static const bool value = sizeof(test<T>(0)) == sizeof(detail::sfinae_types::one); 	typedef typename get_type_name<T, value>::type type; };define_type_check(allocator_type);define_type_check(const_iterator);define_type_check(iterator);define_type_check(reverse_iterator);define_type_check(const_reverse_iterator);define_type_check(const_pointer);define_type_check(const_reference);define_type_check(pointer);define_type_check(reference);define_type_check(value_type);define_type_check(difference_type);define_type_check(size_type);// Okay this example works as expected// just prints 1 for true that std::vector has a type named value_type//#include <iostream>//#include <vector>//#include <boost/type_traits.hpp>//#include "container_traits.hpp"////int main ()//{//	typedef std::vector<int> vec;//	std::cout << tmp::has_value_type<vec>::value << std::endl;//	return 0;//}// And works fine, until I uncomment any one or all of the following lines. Then it starts printing 0's// for the same problem. I don't see whats going on. It still compiles fine, but doesnt print// the correct value any more.//define_type_check(key_compare);     // <-Uncommenting this code line and the program prints the wrong result//define_type_check(key_type);        // <-Uncommenting this code line and the program prints the wrong result//define_type_check(mapped_type);     // <-Uncommenting this code line and the program prints the wrong result//define_type_check(value_compare);   // <-Uncommenting this code line and the program prints the wrong result//define_type_check(container_type);  // <-Uncommenting this code line and the program prints the wrong result// THis is very strange to me. It seems so random.} // end namespace tmp#endif HPP_CONTAINER_TRAITS_03152007
Julian90
Julian90
Ok i cant see anything wrong with the code but i did notice that its only failing when you uncomment types that std::vector doesnt contain. From what i can see the only common link between them is the macro, the sfinae types, and the Wrap template so id suggest...
1) close the project restart your computer then do a clean build and see if it fixes it (compilers get confused sometimes)
2) look at the preprocessed file and try to find an error in the macro
3) move Wrap into the has_type_name template, im not sure why this would make a difference but its a stronger link then the sfinae_types because it gets instantiated for each type

Quote:
Oh, can someone tell me how to view my code after the preprocessor has made its substitutions? I hear of people doing it all the time but i never seen than option in any IDE i've used. Im using VS2005 right now.


Project -> Properties -> C/C++ -> Preprocesor

You may get wierd linker errors when you change it, just ignore them it is still generating the preprocessed file but doesnt update the object files and so the linker (which shouldnt be running but for some reason always does) gets confused.
Amnesty2
Amnesty2
Okay,
I think i've got it working now.
Thanks for pointing out that all the types that were breaking it are the ones not found in vector.

After reading that i tried including map. And everything worked again. Then I commeted out it back out and it still worked? It took me a little bit to rebreak the code. Its just very strange and i still don't understand what the problem is really.

Anyway, putting Wrap back into the class and i havent been able to break the code again.

Thanks you

Ray

PS Sorry about the forum breaking code block. I don't have that class on one line in my source code. I guess \ in the code block is processed.
Julian90
Julian90
your welcome, a hint for next time, the forum will keep it split up if you put a space after the \'s

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.