Reputation: 7321
Currently, I have some code as follows
template<typename Type>
Type* getValue(std::string name, bool tryUseGetter = true)
{
if(tryUseGetter)
{
if(_properties[name]->hasGetter)
{
return (Type*)_properties[name]->getter();
}
return (Type*)_properties[name]->data;
}
else
{
return (Type*)_properties[name]->data;
}
}
Is there a way to make tryUseGetter a compile time switch? i.e. move it to the template declaration so it's something akin to this
template<typename Type, bool tryUseGetter = true>
...
Thanks.
Upvotes: 3
Views: 1135
Reputation: 99715
You could use type cast operator and structure getValue
as follows (usage syntax will be the same as with function) :
template<typename Type, bool tryUseGetter = true>
struct getValue {};
template<typename Type>
struct getValue<Type, true> {
getValue(const std::string& name) : name(name) {};
operator Type*() const {
if(_properties[name]->hasGetter) {
return (Type*)_properties[name]->getter();
}
return (Type*)_properties[name]->data;
}
private:
const std::string& name;
};
template<typename Type>
struct getValue<Type, false> {
getValue(const std::string& name) : name(name) {};
operator Type*() const {
return (Type*)_properties[name]->data;
}
private:
const std::string& name;
};
Usage:
int main () {
int* i = getValue<int>( "TEST" ); // true by default
Xstruct* x = getValue<Xstruct, false>( "XS" ); // false
}
Upvotes: 2
Reputation: 1142
Before you go and make the code all complicated...did you check to see if the optimizing compiler was already doing this for you?
Upvotes: 0
Reputation: 507393
Just in case you really need it (although from a performance point of view, i doubt it would be noticeable), i would overload
template<typename Type>
Type* getValue(std::string const &name)
{
if(_properties[name]->hasGetter)
{
return (Type*)_properties[name]->getter();
}
return (Type*)_properties[name]->data;
}
template<typename Type, bool tryUseGetter>
Type *getValue(std::string const &name)
{
if(tryUseGetter)
{
return getValue<Type>(name);
}
else
{
return (Type*)_properties[name]->data;
}
}
Also, you should first follow the real rules: Pass name
by-const-reference instead of passing a copy, for example.
Upvotes: 4
Reputation: 4542
As an alternative to Dirk's answer, you can put the function in a struct
. Template classes can be partially specialized (in contrast to template functions), so you can write:
template<typename Type, bool tryUseGetter = true>
struct getValue;
template<typename Type>
struct getValue<Type, true>
{
Type* run(std::string name)
{
if(_properties[name]->hasGetter)
{
return (Type*)_properties[name]->getter();
}
return (Type*)_properties[name]->data;
}
};
template<typename Type>
struct getValue<Type, false>
{
Type* run(std::string name)
{
return (Type*)_properties[name]->data;
}
};
Call it as getValue<T>::run("foo")
or getValue<T, false>::run("foo")
.
I'm not 100% certain that it's allowed to have template parameters of the type bool
, so perhaps you should change it to int
.
Upvotes: 6
Reputation: 31061
You can get compile-time dispatch of the "try-use-getter" stuff by splitting your method into two and having the compiler dispatch to the appropriate method:
struct __try_use_getter { }
external const __try_use_getter tryusegetter;
template<typename Type>
Type*
getValue(std::string name, const __try_use_getter&)
{
if(_properties[name]->hasGetter)
{
return (Type*)_properties[name]->getter();
}
return (Type*)_properties[name]->data;
}
template<typename Type>
Type*
getValue(std::string name)
{
return (Type*)_properties[name]->data;
}
With this scenario in place, you would have full compile-time dispatching:
int result = getValue("foo", tryusegetter);
would try the getter first, whereas
int result = getValue("foo");
would immediately call the getter-less version.
Upvotes: 5