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)?
source to share
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.
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) {}
source to share