Happy Green Kid Naps
Happy Green Kid Naps

Reputation: 1683

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;
    }
};

Upvotes: 2

Views: 141

Answers (2)

cpplearner
cpplearner

Reputation: 15928

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()) {}    
};

Upvotes: 3

3CxEZiVlQ
3CxEZiVlQ

Reputation: 38976

Why not

class Foo
{
    std::pair<A, B> ab;
    public:
    Foo() : ab { func() }
    {
    }
};

or

class Foo
{
    A a;
    B b;
    public:
    Foo() : a { func().first }, b { func().second }
    {
    }
};

Upvotes: 0

Related Questions