3

The following code doesn't work. Its intent is to pass arguments to variadic base classes. Is this possible, and if so, what's the right way to implement it? (Clang's error message is: an initializer for a delegating constructor must appear alone, which I don't understand.)

template<class... Visitors>
class Visited: public Visitors...
{
    public:
        template<class F>
        Visited(const F& f): F(f)               {}

        template<class F, class... Rest>
        Visited(const F& f, const Rest&... r):
            F(f), Visited(r...)                       {}
};

struct A {};
struct B {};
struct C {};

int main()
{
    A a;
    B b;
    C c;
    Visited<A,B,C> v(a, b, c);
}
foxcub
  • 2,517
  • 2
  • 27
  • 27

1 Answers1

7

This is much easier and it works with (sufficiently recent versions of) GCC and Clang:

template<class... Args>
Visited(const Args&... args) : Visitors(args)... {}

using one argument per base class. If you want perfect forwarding for the arguments, use the slightly less concise:

template<class... Args>
Visited(Args&&... args) : Visitors(std::forward<Args>(args))... {}

In both cases, consider adding explicit for the case that Visitors is only a single class and you want to avoid accidental conversions.

Live example

Daniel Frey
  • 55,810
  • 13
  • 122
  • 180
  • Magic, in fact the template is not necessary. `Visited(const Visitors&... args): Visitors(args)... {}` works. Thanks! – foxcub May 04 '14 at 22:11
  • @foxcub That might introduce additional temporaries, but if that's not a concern then yes, that is an even easier option. – Daniel Frey May 04 '14 at 22:12
  • @foxcub But then the args are `Visitors`, i.e. you "copy" them "into" your bases (most probably implicitly created `Visitors`) instead of initializing the bases with args. – leemes May 04 '14 at 22:12
  • Interesting. Why are the two forms different? I.e. why does your template version avoid copying, whereas mine doesn't? – foxcub May 04 '14 at 22:19
  • Also how about `Visited(Visitors&&... args): Visitors(args)... {}`, or something like that? Would this avoid copying? – foxcub May 04 '14 at 22:21
  • @foxcub Consider `Visitors` being a class `A` which has a copy-ctor and a constructor taking some other class `B`. In my case, the `B` is passed to the ctor of the base class. No copy of either `A` or `B` is made. In your case, you first construct an `A` (with the passed `B`) for the *argument* (in `args`) and only then do you initialize the base class with this `A`, calling its copy- (or move-)ctor. – Daniel Frey May 04 '14 at 22:22
  • @DanielFrey Ah, understood. Thanks. And it's splitting arguments one by one? I.e., first goes to the first class, second to the second, etc? In this case, I need my version. Visitors may have arbitrarily complicated initialization. – foxcub May 04 '14 at 22:23
  • @DanielFrey To be honest, I wasn't concerned with the perfect forwarding. I can afford copying in this case. But for learning purposes, this is great. Thanks! – foxcub May 04 '14 at 22:24
  • @DanielFrey Thanks. Just so that I'm clear, in both cases it will split the arguments, and forward only one per class? – foxcub May 04 '14 at 22:27
  • @foxcub Yes, it's a 1:1 mapping. A non-1:1-mapping is way more complicated and I'm not sure I can provide an implementation as it depends a lot on the specific use-case. – Daniel Frey May 04 '14 at 22:28
  • @DanielFrey Thanks, this makes a lot of sense. I'll actually need the non-forwarding way. But either way, you've solved my problem. – foxcub May 04 '14 at 22:30