Tag dispatching constructors

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <string>

struct A {
	struct Tag{};
	std::string name;
	int value;
	A (const std::string& n, int v) : name(n), value(v) {}
	A (const std::string& n, int v, Tag) : name(n), value(v) {std::cout << "Constructor with Tag called.\n";}
};

struct B : A {using A::A;};
struct C : B {using B::B;};

struct D : C {
	char special;
	D (const std::string& n, int v, char s) : C(n, v), special(s) {}
	D (const std::string& n, int v, char s, Tag tag) : C(n, v, tag), special(s) {}  // Any way to avoid this repetition?
};

struct E : B {
	double special;
	E (const std::string& n, int v, double d) : B(n, v), special(d) {}
	E (const std::string& n, int v, double d, Tag tag) : B(n, v, tag), special(d) {}  // Again the nuissance!
};

int main() {
	A a("a", 1, A::Tag{});
	B b("a", 2, A::Tag{});
	C c("c", 3, A::Tag{});
	D d("d", 4, 'd', A::Tag{});
	E e("e", 5, 3.14, A::Tag{});
}


How to avoid having to type out a second near-identical constructor for any class like D and E which have specialized constructors different from A? You can imagine the nuissance this causes if there are many classes like D and E (and with many parameters) that need the Tag parameter. The nuisance will be there to when making changes to the constructors. Delegated constructors I don't think will work because of passing `tag` into the parent's constructor (wouldn't help much anyway). Is there some sort of inheritance trick I can apply simultaneously to all such classes to get them all to behave like B and C's constructors?
Last edited on
You can slightly reorder constructor parameters and use template constructor:
1
2
3
4
5
6
7
struct D : C {
	char special;
	template<typename ...Args>
	D (char s, Args&&... args) : C(std::forward<Args>(args)...), special(s) {}
};
//...
D d('d', "d", 4, A::Tag{});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <string>
#include <utility>

struct A {
    struct Tag{};
    std::string name;
    int value;
    A (const std::string& n, int v) : name(n), value(v) {}
    A (const std::string& n, int v, Tag) : name(n), value(v) {std::cout << "Constructor with Tag called.\n";}
};

struct B : A {using A::A;};
struct C : B {using B::B;};

struct D : C {
    char special;
    template < typename ... ARGS >
    D( const std::string& n, int v, char s, ARGS&&... args ) : C( n, v, std::forward<ARGS>(args)... ), special(s) {}
};

struct E : B {
    double special;
    template < typename ... ARGS >
    E( const std::string& n, int v, double d, ARGS&&... args ) : B( n, v, std::forward<ARGS>(args)... ), special(d) {}
};

http://coliru.stacked-crooked.com/a/f0eb82ad8d237988
Topic archived. No new replies allowed.