DarioP
DarioP

Reputation: 5465

How to improve a constructor that takes a compile-time-known condition?

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

Answers (3)

James Kanze
James Kanze

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

Constructor
Constructor

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.

Live demo

Upvotes: 3

borisbn
borisbn

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 >();

http://ideone.com/3CJS41

Upvotes: 0

Related Questions