2

I want to have an std:array of std::function, but I want to make sure that all elements of the array are initialized. For that end I built a wrapper class that takes an std::function as a construction parameter.

But when I initialize an array of my wrapper class directly with my function (the one who should be inside std::function) it fails to compile.

Here is the problem, distilled:

#include <functional>
#include <array>

static void f() {}
using F = std::function<void(void)>;
enum { Count = 4 };

struct C
{
    //To get a compilation error when some
    //  elements of the array are not initialized.
    C() = delete;

    C(F) {}
};

//OK
static const C c {f};

//OK
static const std::array<F,Count> direct
{
    F{f},
    {f},
    f,
    f
};

static const std::array<C,Count> wrapper
{
    F{f},   //OK
    C{f},   //OK
    {f},    //OK
    f       //could not convert 'f' from 'void()' to 'C'
};

I tried changing the array to an std::vector<C> (although it defeats my whole purpose of using an std:array to begin with) and it refuses to compile any of the above initializations.

1

1 Answer 1

6

Unlike C c = f; (which is direct initialization), in aggregate initialization, every element is copy initialized.

Each direct public base, (since C++17) array element, or non-static class member, in order of array subscript/appearance in the class definition, is copy-initialized from the corresponding clause of the initializer list.

That means, the last element of wrapper, which is of type C, is copy-initialized from f; which requiers two implicit conversions. The conversion from the function pointer to F, and the conversion from F to C. Both of them are user-defined conversions, but only one user-defined conversion is allowd in one implicit conversion sequence.

For the same reason C c = f; fails either.

You can add explicit conversion. e.g.

static const std::array<C,Count> wrapper
{
    F{f},   //OK
    C{f},   //OK
    {f},    //OK
    static_cast<F>(f)
};

static const C c {f}; works because it's direct initialization and behaves differently with copy initialization. For direct initialization the constructors of C will be considered and one of them expects an F as parameter, f could be converted to F then anything is fine; only one user-defined conversion is required here.

(emphasis mine)

In addition, the implicit conversion in copy-initialization must produce T directly from the initializer, while, e.g. direct-initialization expects an implicit conversion from the initializer to an argument of T's constructor.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.