我想要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
开头的全部目的),并且拒绝编译上述任何初始化方法。
与C c = f;
(即direct initialization不同,在aggregate initialization中,每个元素都是copy initialized。
每个
direct public base, (since C++17)
数组元素或非静态类成员,按类定义中数组下标/外观的顺序,是初始化列表中相应子句中的copy-initialized。
这意味着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};
之所以起作用是因为它是direct initialization,并且与copy initialization的行为不同。对于直接初始化,将考虑C
的构造函数,其中之一希望将F
作为参数,可以将f
转换为F
,然后一切都很好;这里只需要一个用户定义的转换。
(重点是我的)
此外,复制初始化中的隐式转换必须直接从初始化程序产生T,而例如直接初始化期望从初始化程序到T的构造函数的参数的隐式转换。