Delegated constructors

Consider this code:

#include <iostream>

struct A {
    A(int n, char c, bool b) 
        /* : some complex initialization list that you don't want to repeat. */
        {initialize();}
    A(int n) : A(n, default_char, default_bool) {}
    A(char c) : A(default_int, c, default_bool) {}  // Do not want initialize() called!
    A(bool b) : A(default_int, default_char, b) {}
    A(int n, char c) : A(n, c, default_bool) {}
    A(int n, bool b) : A(n, default_char, b) {}  // Do not want initialize() called!
    A(char c, bool b) : A(default_int, c, b) {}
private:
    static const int default_int = 3;
    static const char default_char = 't';
    static const bool default_bool = true;
    void initialize() {std::cout << "A ctor.\n";}
};

int main() {
    A a(5,'a',false);
    A b(5);
    A c('a');
    A (5,'a');
    A (5,false);
    A ('a',false);
}

      

Suppose I do NOT want to be initialize();

called for some of the constructors (such as those specified in the code). How can I avoid this without repeating the "complicated initialization list" of the constructor A(int,char,bool)

(to avoid future maintenance issues)?

+3


source to share


2 answers


See this question for most of the solution. After that, we can have:

template <typename DoInit>
A(int n, char c, bool b, DoInit do_init) 
/* : some complex initialization list that you don't want to repeat. */
{
    maybe_initialize(DoInit{});
}

void maybe_initialize(std::false_type ) { }
void maybe_initialize(std::true_type ) {
    /* stuff */
}

      

So we have a general case where we want to initialize:

template <typename ... Ts, typename std::enable_if_t<detail::is_included<std::tuple<Ts...>, std::tuple<Year, Month, Day>> ::value>* = nullptr>
A(Ts... ts) :
    A(get_or_default<int>(std::tie(ts...)),
      get_or_default<char>(std::tie(ts...)),
      get_or_default<bool>(std::tie(ts...)),
      std::true_type{})
{}

      



And then a bunch of cases where we don't want that:

A(char c)
: A(default_int, c, default_bool, std::false_type{})
{ }

A(int n, bool b)
: A(n, default_char, b, std::false_type{})
{ }

      

If there are many such cases, you can add a similar condition enable_if_t

for the variational template constructor.

+1




You can assign a private constructor to a class to which all public constructors are delegated. Here the first argument determines whether to initialize:



private:
    A(bool do_initialize, int n, char c, bool b)
        /* initialisers */
    { if (do_initialize) initialize(); }

public:
    A(int n, char c, bool b) : A(true, n, c, b) {}
    A(int n) : A(true, n, default_char, default_bool) {}
    A(char c) : A(false, default_int, c, default_bool) {}  // Do not want initialize() called!
    A(bool b) : A(true, default_int, default_char, b) {}
    A(int n, char c) : A(true, n, c, default_bool) {}
    A(int n, bool b) : A(false, n, default_char, b) {}  // Do not want initialize() called!
    A(char c, bool b) : A(true, default_int, c, b) {}

      

+6


source







All Articles