CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 2 of 4 FirstFirst 1234 LastLast
Results 16 to 30 of 49
  1. #16
    Join Date
    Oct 2008
    Posts
    1,456

    Re: Is this guaranteed to be correct?

    Quote Originally Posted by OReubens
    Also, I'm not 100% sure the id's will be guaranteed identical for types originating from separately compiled units.
    a conforming compiler should guarantee that ( as long as some requirements are fullfilled, see post#3 )

    Quote Originally Posted by JohnW@Wessex
    What I my class is designed to do is this.
    as suggested in post #9, you can avoid the NextUniqueId() function calls, at the cost of either a (possibly small) runtime or space penalty. For example, something like ( c++03 compatible, off the top of my head solution, not tested ! ) :

    Code:
    template< typename T1, typename T2 >
    struct SameType { static const bool value = false; };
    
    template< typename T >
    struct SameType<T,T> { static const bool value = true; };
    
    struct NoType {};
    
    template< typename T, typename T1 = NoType, typename T2 = NoType, typename T3 = NoType > // ... up to some Tmax
    struct TypeMap
    {
    	// return the position, or -1 if not found
    
    	static const unsigned value = SameType<T1,NoType>::value ? -1 : ( SameType<T,T1>::value ? 0 : ( 1 + TypeMap<T,/*T1,*/T2,T3>::value ) );
    };
    
    template< typename T1 = NoType, typename T2 = NoType, typename T3 = NoType > // ... up to Tmax
    struct Any
    {
    	unsigned id;
    	// ...
    
    	template < typename U1, typename U2, typename U3 >
    	bool IsSameType( Any<U1,U2,U3> const& other )
    	{
    		// the compiler should be nice enough to optimize obvious branches and apply lookup/binary search whenever appropriate
    
    		switch( other.id )
    		{
    		case 0: return id == TypeMap<U1,T1,T2,T3>::value;
    		case 1: return id == TypeMap<U2,T1,T2,T3>::value;
    		case 2: return id == TypeMap<U3,T1,T2,T3>::value;
    		default:return false;
    		}
    	}
    };
    or

    Code:
    template< typename A1, typename A2 >
    struct AnyCompare { };
    
    template< typename T1, typename T2, typename T3, typename U1, typename U2, typename U3 >
    struct AnyCompare< Any<T1,T2,T3>, Any<U1,U2,U3> >
    {
    	static const unsigned Map[] =
    		{
    			TypeMap<U1,T1,T2,T3>::value,
    			TypeMap<U2,T1,T2,T3>::value,
    			TypeMap<U3,T1,T2,T3>::value
    		};
    };
    
    // ... possibly more specializations to compress size ( otherwise, for each Any instantiation you'd end up with a Tmax-sized static lookup table )
    
    // ...
    
    	template < typename U1, typename U2, typename U3 >
    	bool IsSameType( Any<U1,U2,U3> const& other )
    	{
    		return id == AnyCompare< Any<T1,T2,T3>, Any<U1,U2,U3> >::Map[ other.id ];
    	}
    };
    the first code has no space overhead and a runtime overhead depending on how much the compiler optimzes the switch, whereas the second code has no runtime overhead but a per-instantiation space overhead varying from 1 to Tmax times your current solution, depending on the AnyCompare specialization.

    Note that you can use the (boost)preprocessor(library) to generate the Tmax dependent boilerplate code ...

  2. #17
    Join Date
    Jul 2002
    Location
    Portsmouth. United Kingdom
    Posts
    2,727

    Re: Is this guaranteed to be correct?

    Thanks for that.
    I'll give it a look over this evening to see if it can be grafted into what I already have.
    "It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
    Richard P. Feynman

  3. #18
    Join Date
    Jul 2002
    Location
    Portsmouth. United Kingdom
    Posts
    2,727

    Re: Is this guaranteed to be correct?

    Quote Originally Posted by superbonzo View Post
    BTW, in "any1.IsSameTypeAs(any3);" given that you know both the type of any1 and any3 you could simply compare the index of the type as declared in the Any<> specialization, eg

    Any<char, short, int> defines a type map f1: char->0, short->1, int->2, let's call id1 the current id
    Any<int, std::string> defines a type map f2: int->0, string>1, let's call id2 the current id

    the two compare equal iff id1 == f1(f2^-1(id2)). So, no need of the GetTypeIdFor() machinery (unless I missed something )
    I've just realised the small, but significant difficulty with that method.

    Any<int, double> any1 = 1;
    Any<double, int> any2 = 1;

    bool b = any1.IsSameTypeAs(any2); // This will return 'false' despite both objects storing an 'int'.

    The purpose of GetTypeIdFor() is to always return the same id for a particular type.

    I could of course disallow comparison of types from different Any template declarations.
    This is probably a reasonable restriction to make in hind-site.
    "It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
    Richard P. Feynman

  4. #19
    Join Date
    Oct 2008
    Posts
    1,456

    Re: Is this guaranteed to be correct?

    Quote Originally Posted by JohnW@Wessex View Post
    bool b = any1.IsSameTypeAs(any2); // This will return 'false' despite both objects storing an 'int'.
    uhm, I'd say no, it will return true instead. The type map machinery in my previous post will exactly compensate for the types reordering ( the composition f1 o f2^-1 as in the example above ).

    IOW,

    Any<int, double> any1 = 1; // type map f1: int->0, double->1, id = 0
    Any<double, int> any2 = 1; // type map f2: double->0, int->1, id = 1

    the comparison reads 0 == ( 1 --f2^-1--> int --f1--> 0 ), that is true
    Last edited by superbonzo; August 27th, 2014 at 10:38 AM. Reason: added IOW

  5. #20
    Join Date
    Jul 2002
    Location
    Portsmouth. United Kingdom
    Posts
    2,727

    Re: Is this guaranteed to be correct?

    Quote Originally Posted by superbonzo View Post
    uhm, I'd say no,
    I've only had a chance to briefly skim your code so I probably misunderstood your method
    "It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
    Richard P. Feynman

  6. #21
    Join Date
    Jul 2002
    Location
    Portsmouth. United Kingdom
    Posts
    2,727

    Re: Is this guaranteed to be correct?

    @superbonzo

    I had a chance to look at your suggestions this morning, and, like a lot of good ideas, its seems obvious once you know the solution.

    With a couple of minor changes it grafted in perfectly
    "It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
    Richard P. Feynman

  7. #22
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    4,626

    Re: Is this guaranteed to be correct?

    it may work... it just appears like an even more elaborate runtime typecheck when (unless I'm missing something) everything seems statically typed.

    I originally misunderstood your approach as trying to making something akin to a tuple, but you're looking for something akin to a variant.

    Why not have your any:
    Hold a type indicating which type is being stored
    a Union (assuming it's all POD's) or tuple (if complex types) for the actual data.
    .

    Then rather than dynamically determining an ID at runtime (causing it to be a variable), have your class require a template specialization for the type id.

    You'll have to explicitely write the specialisations and take care of making the id's unique yourself, but it'll reduce the 'is same type' check to a byte/byte (or int/int) comparison.


    quick hack. it works, it could be prettier
    Code:
    // Definition for generic template for getTypeId()   (do not provide a generic implementation)
    template <typename T>
    int getTypeId();
    
    // specializations  make sure all return values are unique
    template <> int getTypeId<int>() { return 1; }
    template <> int getTypeId<char>() { return 2; }
    template <> int getTypeId<double>() { return 3; }
    template <> int getTypeId<bool>() { return 4; }
    // add more here.
    
    template <typename T1, typename T2, typename T3>
    class Any
    {
    public:
         int storageType;
    
        Any&  operator=(T1 t) { storageType=getTypeId<T1>(); t1=t; return *this; }
        Any&  operator=(T2 t) { storageType=getTypeId<T2>(); t2=t; return *this; }
        Any&  operator=(T3 t) { storageType=getTypeId<T3>(); t3=t; return *this; }
    
    	template <typename OtherT1,typename OtherT2, typename OtherT3>
    	bool IsSame(const Any<OtherT1,OtherT2,OtherT3>& other) { return storageType==other.storageType; }
    
    	union { T1 t1; T2 t2; T3 t3; };// or tuple/struct
    };
    
    
    int main()
    {
    	Any<int, char, double> a1;
    	a1=1;
    	Any<double, int, bool> a2;
    	a2=2;
    
    	bool b1 = a1.IsSame(a2); // true (int & int)
    	a1=4.0;
    	bool b2 = a1.IsSame(a2); // false (double & int)
    	a2=6.0;
    	bool b3 = a1.IsSame(a2); // true (double & double)
    
    	return 0;
    }

  8. #23
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    4,626

    Re: Is this guaranteed to be correct?

    if you really need the id's to be unique without programmer intervention (you'll still need to define all the specialisations)
    then you could use one of the compiler macro's as a id (assuming all specialisations are in 1 source file)
    such as __LINE__ or you could use __COUNTER__

  9. #24
    Join Date
    Oct 2008
    Posts
    1,456

    Re: Is this guaranteed to be correct?

    well, the "make sure all return values are unique", the "add more here" and the "you'll still need to define all the specialisations" parts look like a no-go as far as the OP is concerned. As far as I got it, this is exactly what he wanted to avoid in the first place.

    Actually, I think there is a better way, by defining

    Code:
    template < typename T >
    struct Type
    {
        static inline void* Id() { return reinterpret_cast<void*>(Id); }
    };
    and using void* ( or a convertible type thereof ) as an identifier in the Any instance, it should work ok ( also thread safe in c++03 ) and the linker should be smart enough to eliminate any space overhead from the final executable.

  10. #25
    Join Date
    Jul 2002
    Location
    Portsmouth. United Kingdom
    Posts
    2,727

    Re: Is this guaranteed to be correct?

    Quote Originally Posted by OReubens View Post
    Why not have your any:
    Hold a type indicating which type is being stored
    a Union (assuming it's all POD's) or tuple (if complex types) for the actual data.

    Then rather than dynamically determining an ID at runtime (causing it to be a variable), have your class require a template specialization for the type id.
    That's actually very similar to what I already had, except that instead of a union I have a data area sized to the largest type (and aligned to a 32bit boundary)
    When a value is stored it uses a 'placement new' to copy construct the value in the data area.

    Using superbonzo's technique, the type ids are now defined as constants at compile time rather than assigning them from a static function & variable at runtime. The only per-instance RAM overhead I have is one byte for the stored type id plus the difference in size between the largest and stored type.

    , but it'll reduce the 'is same type' check to a byte/byte (or int/int) comparison.
    As the type ids are contiguous integers the switch->case->byte/const byte comparison is likely to be pretty efficient.

    "It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
    Richard P. Feynman

  11. #26
    Join Date
    Jul 2002
    Location
    Portsmouth. United Kingdom
    Posts
    2,727

    Re: Is this guaranteed to be correct?

    Quote Originally Posted by superbonzo View Post
    Actually, I think there is a better way,
    That's an interesting idea, though I still have the niggling doubt in the back of my mind that there may be the possibility of getting more than one instance of Id() for a particular type. I could be wrong.
    "It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
    Richard P. Feynman

  12. #27
    Join Date
    Oct 2008
    Posts
    1,456

    Re: Is this guaranteed to be correct?

    ... and I have some doubts concerning the portability of the comparison of the so obtained void* in this case ... and even if the code were perfectly legal and guaranteed, I'd be not surprised to discover that some compilers/linkers doesn't like it anyway. So, yes, kind of risky without some further investigation ...

  13. #28
    Join Date
    Jul 2013
    Posts
    576

    Re: Is this guaranteed to be correct?

    Quote Originally Posted by JohnW@Wessex View Post
    I'm experimenting with a class similar in some ways to Boost::any, but more resource and performance friendly to our embedded platform.
    Again, one of the most prominent characteristics of C++ is its type safety. It's amazing how much effort is spent on giving that away for nothing. It would be much better if all this effort went into making good solid designs instead.

    Boost::Any is a bad idea from start to finish. If people cannot design without downcasting then they should be forced to do so explicitly so it can be detected and corrected at the next code review. So for the sake of your platform I hope you drop this malign "feature".
    Last edited by razzle; August 29th, 2014 at 02:36 AM.

  14. #29
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    4,626

    Re: Is this guaranteed to be correct?

    Quote Originally Posted by superbonzo View Post
    Actually, I think there is a better way, by defining
    Yes, I did think of something like this too but... It won't work if you're dealing with multiple loadable modules (such as dll's) (yes, occupational thing, I'm always concerned about how code behaves if multiple dll's come to play :-))

  15. #30
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    4,626

    Re: Is this guaranteed to be correct?

    Quote Originally Posted by JohnW@Wessex View Post
    That's an interesting idea, though I still have the niggling doubt in the back of my mind that there may be the possibility of getting more than one instance of Id() for a particular type. I could be wrong.
    Well... if yes, then your idea won't work either.
    This is a function, so is your constructor approach in #1.
    So if this fails, your #1 would fail in the exact same way.

    I can confirm that if you're dealing with dll's or libs, that this approach is indeed not guaranteed, depending on how you export things from the dll or lib.

Page 2 of 4 FirstFirst 1234 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured