Reputation: 586
I am writing a template to get value from a collection that can hold different data types. for ex a variant structure. But i get a warning when the compiler generates code for assignments with other types. for ex
struct Variant
{
enum Type
{
_bool,
_int
};
Type type;
union VAL
{
bool bVal;
int nVal;
}val;
};
template <typename ValType>
void GetValue(Variant v, ValType val)
{
if(v.type == Variant::_bool)
{
val = v.val.bVal;
}
else if(v.type == Variant::_int)
{
val = v.val.nVal; // C4800
}
}
Variant v;
v.type = Variant::_bool;
v.val.bVal = true;
bool bVal(false);
GetValue(v, bVal);
Warning:
warning C4800: 'int' : forcing value to bool 'true' or 'false' (performance warning)
Can someone suggest on how can the template be re written to get value the right way ?
Upvotes: 1
Views: 1125
Reputation: 302767
First, as dyp already suggested in the comments, I would recommend looking at Boost.Variant
.
That said, the issue you're running into is that regardless of what type you're storing internally, every branch always has to be compiled the way you wrote it - and some of those branches might not make any sense (what if you added an array or some other POD type?) The way Boost solves this issue is by requiring the user to pass in a functor, and you call that functor with the right type:
template <typename F>
void visit(Variant v, F visitor)
{
if(v.type == Variant::_bool) {
visitor(v.val.bVal);
}
else if(v.type == Variant::_int) {
visitor(v.val.nVal);
}
// etc.
}
So then, you just write a visitor:
struct get_bool {
void operator()(bool b) {
bVal = b;
}
template <typename OTHER>
void operator()(OTHER ) { }
bool& bVal;
};
And use it:
bool bVal(false);
visit(v, get_bool{bVal});
Upvotes: 1
Reputation: 24936
In your template for GetValue
for ValType === bool
, val
is of type bool.
Thus the line val = v.val.nVal;
results in the warning.
In order to provide special code for special types, there is template specialization.
You can specialize the function template like
template<class T>
void GetValue(Variant v, T & val);
template<>
void GetValue<int>(Variant v, int & val)
{
if (v.type == Variant::_int)
val = v.val.nVal;
}
template <>
void GetValue<bool>(Variant v, bool & val)
{
if (v.type == Variant::_bool)
val = v.val.bVal;
}
Note: v.type
does not determine which one will be called, the argument does.
Upvotes: 3