Search code examples
c++if-statementconditional-statementsconstexprtemplate-meta-programming

Conditionally defined variable (static if)


In multiple cases I would want to use something like

template<bool condition>
struct S
{
  int value;
  if constexpr(condition) /*#if condition*/
    double my_extra_member_variable;
  /*#endif*/
}

or

if constexpr(sizeof...(Ts) != 0)
  // define something extra ( a tuple or so )

This is possible with preprocessor flags, but we want to be the "cool kids" that don't use preprocessor flags, but rather metaprogramming

It could also work with specilizations in some cases, but assume you have multiple conditions, and multiple member variables that need to be conditionally activated, it could get nasty quite fast.

I tried

constexpr in_series_production_mode = false;
struct dummy{ dummy(auto& x){}; operator=(auto& x){return *this;} }; /*1 byte*/
struct debug_data_t { /* lots of parameters with big size*/};

template <typename T>
using maybe_empty = typename std::conditional<in_series_production_mode ,T,dummy>::type; 

maybe_empty<debug_data_t> my_debugging_variable; 

But with that you still get 1 byte for the unused dummy variable. While if you used #if of something similar you would have needed 0 bytes.

Does anybody know a better practice for that?


Solution

  • In C++20, the "good enough" solution is with the [[no_unique_address]] attribute

    struct empty_t {};
    
    template<bool condition>
    struct S {
        [[no_unique_address]] std::conditional_t<condition, double, empty_t> var;
    };
    

    It's not perfect because var is always defined, but it will not take any space. Note that if there are multiple variables, you will need them to be different types, e.g.

    template<int>
    struct empty_t {};
    
    template<bool condition>
    struct S {
        [[no_unique_address]] std::conditional_t<condition, double, empty_t<0>> var; 
        [[no_unique_address]] std::conditional_t<condition, double, empty_t<1>> rav;
    };