Невозможно создать класс из std :: function при использовании внутри std :: array - PullRequest
2 голосов
/ 30 октября 2019

Я хочу иметь std:array std::function, но я хочу убедиться, что все элементы массива инициализированы. Для этого я построил класс-оболочку, который принимает std::function в качестве параметра конструкции.

Но когда я инициализирую массив моего класса-оболочки непосредственно с моей функцией (той, которая должна быть внутри std::function)он не может скомпилироваться.

Вот проблема, искаженная:

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

Я попытался изменить массив на std::vector<C> (хотя это полностью противоречит моей цели использования std:arrayдля начала), и он отказывается компилировать любую из вышеуказанных инициализаций.

1 Ответ

6 голосов
/ 30 октября 2019

В отличие от C c = f; (что означает прямая инициализация ), в совокупной инициализации каждый элемент копируется, инициализируется .

Каждый direct public base, (since C++17) элемент массива или нестатический член класса в порядке индекса / появления массива в определении класса инициализируется копией из соответствующего предложения списка инициализатора.

Это означает, что последний элемент wrapper, который имеет тип C, инициализируется копией из f;который требует двух неявных преобразований. Преобразование из указателя функции в F и преобразование из F в C. Оба они являются пользовательскими преобразованиями, но в одной неявной последовательности преобразования допускается только одно пользовательское преобразование.

По той же причине C c = f; также не срабатывает.

Вы можете добавить явноепреобразование. Например,

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

static const C c {f}; работает, потому что это прямая инициализация и ведет себя иначе с копировать инициализацию . Для прямой инициализации будут рассматриваться конструкторы C, и один из них ожидает F в качестве параметра, f может быть преобразовано в F, тогда все в порядке;здесь требуется только одно пользовательское преобразование.

(выделено мной)

Кроме того, неявное преобразование при инициализации копирования должно генерировать T непосредственно из инициализатора , в то время как, например, прямая инициализация ожидает неявного преобразования инициализатора в аргумент конструктора T .

...