-
August 26th, 2014, 04:05 AM
#1
Is this guaranteed to be correct?
I thought I'd get others to check this over as I'm not totally convinced that this is guaranteed to work in all cases.
I have code that generates a unique id for a type. All code in all translation units must receive the same type id for a particular type.
In a .cpp file I have:-
Code:
uint8_t NextUniqueId()
{
static uint8_t uniqueId(0);
return uniqueId++;
}
This returns a new id for each call.
In the .h file I have:-
Code:
template <typename T>
uint8_t GetTypeIdFor()
{
static uint8_t id(NextUniqueId());
return id;
}
This should return a unique id for a type.
Code:
unit8_t typeId = GetTypeIdFor<int>();
My question:-
If several cpp files include this header, will it be guaranteed that the returned ids for types will be identical across all translation units?
My concern is that different translation units may have their own copy of 'GetTypeIdFor<int>' possibly resulting in non-identical type ids.
Thoughts?
"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
-
August 26th, 2014, 04:39 AM
#2
Re: Is this guaranteed to be correct?
Some background to the problem.
I'm experimenting with a class similar in some ways to Boost::any, but more resource and performance friendly to our embedded platform.
It's implemented as a sort of 'enhanced' union where the id of the current type is stored internally.
Example
Code:
Any<char, short, int> any1;
Any<char, short, int> any2;
Any<int, std::string> any3;
any1 = 1;
any2 = 2;
any3 = 3;
any1.IsSameTypeAs(any2); // Should be 'true'.
any1.IsSameTypeAs(any3); // Should be 'true'.
Where 'IsSameTypeAs' compares the internal type ids.
This should be true regardless of where the 'Any' instances are defined or declared.
Last edited by JohnW@Wessex; August 26th, 2014 at 04:49 AM.
"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
-
August 26th, 2014, 04:58 AM
#3
Re: Is this guaranteed to be correct?
Originally Posted by c++std
If D is a template and is defned in more than one translation unit [...] If the defnitions of D satisfy all these requirements,
then the program shall behave as if there were a single defnition of D. If the defnitions of D do not satisfy these requirements, then the behavior is undefned.
the said requirements essentially being having the same tokens and resulting in the same name lookup ( that is true for your use case; pathologies may arise when T-dependent lookups kick in, like, say, if one includes different trait definitions/ADL activated functions or the like ).
BTW, note that your code is not thread-safe.
(ehy, is it just me, or the forum is slow as hell today !? )
-
August 26th, 2014, 05:16 AM
#4
Re: Is this guaranteed to be correct?
Thanks, that's good to hear.
Our code is single threaded, though there are many interrupts.
Thanks for reminding me about that.
"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
-
August 26th, 2014, 10:25 AM
#5
Re: Is this guaranteed to be correct?
This will only ensure unique id's for a certain type, in so far as the type is static.
for dynamic (anonymous) types, it'll keep generating new id's.
if you are loading and unloading dll's using this, then it'll fail there as well.
Also note that while a type may be static, it may not be uniquely instantiated. It is possible that the same type gets explicitely instantiated in every dll. (typical when using template types in multiple dll's).
if you want to compare type equality, then you can do this via the RTTI system (as a general case), via template checks (for the static/compile time case), or via the new c++11 features (decltype, result_of(), typeof, ...)
Also, your system may break for nested or inherited types, depending on how you were expecting them to behave.
-
August 26th, 2014, 11:15 AM
#6
Re: Is this guaranteed to be correct?
Originally Posted by OReubens
This will only ensure unique id's for a certain type, in so far as the type is static.
for dynamic (anonymous) types, it'll keep generating new id's.
That's fine.
if you are loading and unloading dll's using this, then it'll fail there as well.
This is for an ARM based board with no OS, single threaded with a few interrupts, and a message passing cooperative scheduler.
if you want to compare type equality, then you can do this via the RTTI system (as a general case), via template checks (for the static/compile time case), or via the new c++11 features (decltype, result_of(), typeof, ...)
I couldn't find a way to use RTTI that didn't incur unacceptable time or space requirements.
std::type_info was not really up to the job.
dynamic_cast can't be used as the types can be unrelated.
Our cross compiler does not support any C++11 features, and probably won't for some time.
Also, your system may break for nested or inherited types, depending on how you were expecting them to behave.
That's something I will have to add to the unit tests.
"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
-
August 26th, 2014, 11:20 AM
#7
Re: Is this guaranteed to be correct?
Originally Posted by JohnW@Wessex
I couldn't find a way to use RTTI that didn't incur unacceptable time or space requirements.
std::type_info was not really up to the job.
As in the cost of typeid and conversion to std::type_index was too high?
-
August 27th, 2014, 03:27 AM
#8
Re: Is this guaranteed to be correct?
Originally Posted by laserlight
As in the cost of typeid and conversion to std::type_index was too high?
Possibly. It's not clear what is going on behind the scenes. If it's just using the hash_code and the generation of the type_info is at compilation time then that would have been a perfect solution...except that it is C++11 only.
One thing that concerned me about the hash_code is this paragraph from CPP Reference.
Returns an unspecified value, which is identical for the type_info objects referring to the same type. No other guarantees are given.
This seems to imply that the hash code may be shared by another type, which would make it useless for my needs anyway. Could std::type_index suffer the same problem? It's not clear.
I think what I have is going to tick most of the boxes of a 'useful' variant type.
That's the compromise you often have to make in the embedded world; A pragmatic decision based on getting the maximum number of useful features for the least cost.
"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
-
August 27th, 2014, 03:53 AM
#9
Re: Is this guaranteed to be correct?
Originally Posted by JohnW@Wessex
This seems to imply that the hash code may be shared by another type, which would make it useless for my needs anyway. Could std::type_index suffer the same problem? It's not clear.
yes, the only goal of hash_code is to provide a good hash function for unordered containers, that is to provide uniformity and low ( but not zero ) collision probability.
conversely, type_index ( and type_info ) must support "true" equality, in order to be properly used into associative containers.
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 )
-
August 27th, 2014, 04:37 AM
#10
Re: Is this guaranteed to be correct?
Originally Posted by JohnW@Wessex
This seems to imply that the hash code may be shared by another type, which would make it useless for my needs anyway. Could std::type_index suffer the same problem? It's not clear.
Yes it's clear.
The type_index was introduced as a unique identifier of a type_info (since the hash_code didn't serve this purpose).
Furthermore the hash_code of a type_info is the same as the hash_code of a type_index of the same type_info.
-
August 27th, 2014, 04:41 AM
#11
Re: Is this guaranteed to be correct?
Originally Posted by JohnW@Wessex
I'm experimenting with a class similar in some ways to Boost::any, but more resource and performance friendly to our embedded platform.
That's not a very good idea. It just encourages a non type safe usage of C++.
Last edited by razzle; August 29th, 2014 at 12:56 AM.
-
August 27th, 2014, 05:27 AM
#12
Re: Is this guaranteed to be correct?
Actually the implementation has a lot of type safety. That was one of the goals I had in mind.
I have static asserts that will ensure a compile error if an unsupported type is requested.
Code:
int i;
i = variant.Get<int>(); // This will fail to compile if 'variant' does not support 'int'.
i = int(variant); // This will fail to compile if 'variant' does not support 'int'.
variant = i; // This will fail to compile if 'variant' does not support 'int'.
An exception will be thrown if the type requested is supported but not the currently stored type.
Code:
double d;
variant = 1; // 'int' & 'double' supported.
d = variant; // Throw exception.
d = variant.Get<double>(); // Throw exception.
It implements a build-in visitor base class that allows type safe callbacks.
Code:
class Reader : public Variant<char, int>::Reader
{
public:
void Read(int i) { }
void Read(char c) { }
};
Reader reader;
variant.Call(reader);
"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
-
August 27th, 2014, 08:14 AM
#13
Re: Is this guaranteed to be correct?
Since you only seem to be concerned about static types... (#6) and both the samples in #1 and #2 seem to confirm this.
Why aren't you using static (compile time) verifications between the types ? Should be fairly easy to implement, and the advantage is that it takes NO extra code to be executed (though it will burden the compiler a bit), the test will simply result in a static true/false constant. If would allow both runtime tests (as in #1) as well as compile time tests and static_assert()s.
The only way that could not be the case is if you are indeed using the types dynamically through a base class and passing base pointers/references around and then trying to upcast them back to the original type (=a bad idea since that probably takes a huge switch or if/else cascade. If so, there is probably a better solution to the design if this is the case).
Also, I'm not 100% sure the id's will be guaranteed identical for types originating from separately compiled units. I'm having a suspicion it'll generate different id's for identical types in different modules. A smart linker might resolve that anyway, but then we're entering the 'compiler/linker dependant' behaviour' dilemma. Again, this may not be an issue to you.
Imo, the attempt to try and get a static typing identification based on a dynamically generated type id is "asking for problems somewhere down the road", especially if you want this to be portable. Again, may not be an issue to you.
-
August 27th, 2014, 08:45 AM
#14
Re: Is this guaranteed to be correct?
The code below will work for (typed) variables. It can't work entirely static since variables never are, only types are.
the alternative is to call std::is_same directly if you have a type.
Code:
#include <type_traits>
template <class first, class second>
bool sametype(const first& /*f*/, const second& /*s*/)
{
return std::is_same<first, second>::value;
}
int main()
{
any<int, int, double> iid1;
any<int, int, double> iid2;
any<int, double, double> idd;
bool b1 = sametype(iid1,iid2); // true
bool b2 = sametype(iid1,idd); // false
}
depends a bit on your compiler, but it'll pretty much result in a static true/false, or at worse in a call to a function returning true or false.
-
August 27th, 2014, 09:27 AM
#15
Re: Is this guaranteed to be correct?
Your example isn't solving the same problem as what I was describing.
What I my class is designed to do is this.
(Types in the template parameter list must be unique; no duplicates)
Code:
int main()
{
any<int, char, double> icd1;
any<int, char, double> icd2;
icd1 = 1; // Assign an int.
icd2 = 2; // Assign an int.
bool b1 = icd1.IsSameTypeAs(icd2); // true
icd1 = 2.2; // Assign a double.
bool b2 = icd1.IsSameTypeAs(icd2); // false
}
"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
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|