为递归定义的类数组 class 模拟聚合初始化
Emulate aggregate initialization for recursively-defined array-like class
考虑:
template <std::size_t r,std::size_t d>
struct Tensor
{
Tensor<r-1u,d> Data[d];
};
template <std::size_t d>
struct Tensor<0u,d>
{
double Data;
};
我们可以使用复制列表初始化来初始化这样一个 Tensor
这样的:
Tensor<2u,3u> t= { 1.0, 2.0, 3.0,
4.0, 5.0, 6.0,
7.0, 8.0, 9.0 };
注意大括号省略。
这也适用于通用编程上下文,例如:
template <typename... T,
typename= std::enable_if_t<(std::is_same_v<T,double> && ...) && (sizeof...(T)==9u)>>
Tensor<2u,3u> MakeTensor(T... x) { return {x...}; }
但是,如果 Data
是私有的,Tensor
将不再是聚合,因此上述语法将无效。
在那种情况下,是否可以通过编程方式恢复此行为?
聚合初始化只适用于聚合,所以不,严格来说,这是不可能的。
您可以通过提供 initializer_list/variadic 模板构造函数或通过仅出于初始化目的采用张量数据结构的聚合版本的构造函数来模拟它,例如:
template <std::size_t r,std::size_t d>
struct RawTensor
{
std::array<RawTensor<r-1u,d>,d> data;
};
template <std::size_t d>
struct RawTensor<0u,d>
{
double data;
};
template <std::size_t r,std::size_t d>
struct Tensor
{
Tensor( RawTensor<r,d> const& data ): data_{data}{}
private:
RawTensor<r,d> data_;
};
template <typename... T,
typename= std::enable_if_t<(std::is_same_v<T,double> && ...) && (sizeof...(T)==9u)>>
RawTensor<2u,3u> MakeTensor(T... x) { return {x...}; }
Tensor<2u,3u> t1 = RawTensor<2u,3u>{ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 };
Tensor<2u,3u> t2 = MakeTensor( 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 );
并让编译器对其进行优化。如果您的初衷是利用 operator[] 的链接(因此您需要嵌套数据为 Tensor 类型),它仍然是可能的,但需要不那么琐碎的初始化逻辑。
考虑:
template <std::size_t r,std::size_t d>
struct Tensor
{
Tensor<r-1u,d> Data[d];
};
template <std::size_t d>
struct Tensor<0u,d>
{
double Data;
};
我们可以使用复制列表初始化来初始化这样一个 Tensor
这样的:
Tensor<2u,3u> t= { 1.0, 2.0, 3.0,
4.0, 5.0, 6.0,
7.0, 8.0, 9.0 };
注意大括号省略。
这也适用于通用编程上下文,例如:
template <typename... T,
typename= std::enable_if_t<(std::is_same_v<T,double> && ...) && (sizeof...(T)==9u)>>
Tensor<2u,3u> MakeTensor(T... x) { return {x...}; }
但是,如果 Data
是私有的,Tensor
将不再是聚合,因此上述语法将无效。
在那种情况下,是否可以通过编程方式恢复此行为?
聚合初始化只适用于聚合,所以不,严格来说,这是不可能的。
您可以通过提供 initializer_list/variadic 模板构造函数或通过仅出于初始化目的采用张量数据结构的聚合版本的构造函数来模拟它,例如:
template <std::size_t r,std::size_t d>
struct RawTensor
{
std::array<RawTensor<r-1u,d>,d> data;
};
template <std::size_t d>
struct RawTensor<0u,d>
{
double data;
};
template <std::size_t r,std::size_t d>
struct Tensor
{
Tensor( RawTensor<r,d> const& data ): data_{data}{}
private:
RawTensor<r,d> data_;
};
template <typename... T,
typename= std::enable_if_t<(std::is_same_v<T,double> && ...) && (sizeof...(T)==9u)>>
RawTensor<2u,3u> MakeTensor(T... x) { return {x...}; }
Tensor<2u,3u> t1 = RawTensor<2u,3u>{ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 };
Tensor<2u,3u> t2 = MakeTensor( 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 );
并让编译器对其进行优化。如果您的初衷是利用 operator[] 的链接(因此您需要嵌套数据为 Tensor 类型),它仍然是可能的,但需要不那么琐碎的初始化逻辑。