Reputation: 5465
I have a constructor that looks like this:
SomeType(const bool condition = true) {
if (condition) {
// do some init
} else {
// do some other init
}
}
But as condition
is known at compile time I suspect that this could be improved avoiding to pass a variable and evaluate the if statement at run time. Is this true? How could it be done?
Upvotes: 4
Views: 182
Reputation: 153929
If the condition is always a compile time constant, you can do something like:
class SomeType
{
void initTrue() {}
void initFalse() {}
public:
template <bool C>
struct Discrim {}
SomeType( Discrim<true> ) { initTrue(); }
SomeType( Discrim<false> ) { initFalse(); }
};
You would then have to invoke it with:
SomeType((SomeType::Discrim<condition>()));
Or you could simply define two enums, on which you could overload the constructor:
class SomeType
{
void initTrue() {}
void initFalse() {}
public:
enum ConditionTrue { conditionTrue };
enum ConditionFalse { conditionFalse };
SomeType( ConditionTrue ) { initTrue(); }
SomeType( ConditionFalse ) { initFalse(); }
};
Or you can just do what you're doing; it's highly unlikely that
the extra test will add a measurable difference to the run time.
And if it does (as shown by the profiler), it can only be that
the constructor is small enough to be inlined (in which case,
constant propagation in the optimizer will ensure that there is
no actual if
). The above techniques are typically only useful
when you want separate constructors which have distinctly
different initialization lists.
Upvotes: 1
Reputation: 7473
There is no syntax in C++ to call a simple templated constructor like
struct SomeType
{
template <bool condition>
SomeType();
};
template<>
SomeType::SomeType<true>()
{
// do some init
}
template<>
SomeType::SomeType<false>()
{
// do some other init
}
// ...
SomeType<true> st; // this syntax is used to create an object of a class template:
// template <bool>
// struct SomeType
// {
// };
One well-known workaround is to imitate template specialization via function overloading:
#include <type_traits>
struct SomeType
{
SomeType(std::true_type)
{
// do some init
}
SomeType(std::false_type)
{
// do some other init
}
template <bool condition>
static SomeType New()
{
return SomeType(std::integral_constant<bool, condition>{});
}
};
Example of use:
auto st = SomeType::New<false>();
In this code C++11 std::integral_constant
template class from type_traits
header is used but it is simply enough to write a similar class template in C++03.
Upvotes: 3
Reputation: 5054
If you don't trust to compiler then you (maybe) can do your class's constructor as a template:
template< bool condition >
SomeType();
template<>
SomeType< true >() {
// do some init
}
template<>
SomeType< false >() {
// do some other init
}
Edit: As @Constructor (the name says it all))) said you can't call this type of constructor. Therefore you can move all initialization in function. Like this:
struct SomeType {
template< bool condition >
void init();
};
template<>
void SomeType::init< true >() {
// do some init
}
template<>
void SomeType::init< false >() {
// do some other init
}
SomeType t;
t.init< true >();
SomeType f;
f.init< false >();
Upvotes: 0