Search code examples
c++structured-bindingsctor-initializer

Structured binding in constructor initialization list?


This is similar in vein to Is it possible to use structured binding in the member initializer list of a constructor?, except that in my case, it is not a dislike-versus-like scenario rather it is a how-to-solve-it question.

I have two classes that I cannot touch and a free-standing function that constructs one object of each type and returns them as a pair:

#include <utility>

struct A
{
    A() = delete;
    explicit A(int) {}
};

struct B
{
    B() = delete;
    explicit B(char) {}
};

std::pair<A, B> func() // Same issue when pair is replaced with tuple
{
    return { A{42}, B{'F'} };
}

I can touch neither A nor B. func() does a good amount of common work to construct objects of A and B.

Now to the problem at hand, showing my different attempts:

Attempt 1: Try structured binding in ctor initializer-list

class Foo
{
    A a;
    B b;
    public:
    Foo() : [a, b] { func() }
    // error: expected identifier before '[' token
    // Not resolved when '{func()}' is replaced with '= func()' or '(func))'
    {
    }
};

Attempt 2: Use std::tie in lieu of structured binding

class Foo
{
    A a;
    B b;
    public:
    Foo() : std::tie(a, b) = func() }
    // error: expected class-name before '(' token at column 21
    {
    }
};

Attempt 3: Construction within body, but (of course) it won't work

// error: use of deleted functions 'A::A()' and 'B:B()'
class Foo
{
    A a;
    B b;
    public:
    Foo()
    {
        const auto& p{func()};
        a = p.first;
        b = p.second;
    }
};


Solution

  • The traditional approach is to use a delegating constructor.

    class Foo
    {
        A a;
        B b;
        Foo(std::pair<A, B> p) : a(p.first), b(p.second) {}
    
    public:
        Foo() : Foo(func()) {}    
    };