C++ 基于可变模板的通用聚合初始化
这是一个有趣的问题,我刚才还在想。 给定具有基础聚合的C++ 基于可变模板的通用聚合初始化,c++,templates,c++11,c++14,variadic-templates,C++,Templates,C++11,C++14,Variadic Templates,这是一个有趣的问题,我刚才还在想。 给定具有基础聚合的结构: #include <array> template <typename T, size_t N> struct A { constexpr A() = default; template <typename ... Ts> constexpr A(const T& value, const Ts& ... values); // magic std::a
结构
:
#include <array>
template <typename T, size_t N>
struct A
{
constexpr A() = default;
template <typename ... Ts>
constexpr A(const T& value, const Ts& ... values); // magic
std::array<T, N> arr; // aggregate
};
这里有一种方法是有效的,但几乎可以肯定会有所改进 我们有一个
a
的构造函数,它接受一个参数包,将每个元素转换成一个元组,将元组连接在一起形成一个大元组,然后简单地使用该大元组的聚合初始化。以下所有内容都可以是constexpr
,为了简洁起见,我省略了它
首先,我们进行转换:
template <class... Us>
A(Us const&... us)
: A(std::tuple_cat(as_tuple(us)...))
{ }
模板
A(美国常数和…美国)
:A(std::tuple\u cat(as\u tuple(us)…)
{ }
与:
//单参数
模板
自动作为元组(常量和单位){
return std::forward_as_tuple(u);
}
//聚合参数
模板
自动作为元组(常量和A){
以元组形式返回(a,std::make_index_sequence{});
}
模板
自动作为元组(常量和A,标准::索引序列){
返回std::forward_as_tuple(std::get(a.arr)…);
}
然后我们从这里开始初始化:
template <class... Us, class = std::enable_if_t<(sizeof...(Us) <= N)>>
A(std::tuple<Us...> const& t)
: A(t, std::index_sequence_for<Us...>{})
{ }
template <class... Us, size_t... Is>
A(std::tuple<Us...> const& t, std::index_sequence<Is...> )
: arr{{std::get<Is>(t)...}}
{ }
template巴里的回答肯定是正确的,可以接受。但它需要添加一些C++14库(您也可以自己用C++11编写),并且总体上需要一些好的tuple
-和元编程
让我们将多个参数视为“范围的范围”,其中范围只是一个指针和一个大小。标量参数只是大小1范围,而a
参数是size-N范围
template<class T>
struct Range
{
T const* data_;
std::size_t size_;
constexpr T const* begin() const noexcept { return data_; }
constexpr T const* end() const noexcept { return data_ + size_; }
constexpr std::size_t size() const noexcept { return size_; }
};
template<class T>
constexpr Range<T> as_range(T const& t)
{
return { &t, 1 };
}
template<class T, std::size_t N>
struct A;
template<class T, std::size_t N>
constexpr Range<T> as_range(A<T, N> const& a)
{
return { a.arr, N };
}
模板
结构范围
{
T常数*数据;
标准:尺寸;
constexpr T const*begin()const noexcept{返回数据}
constexpr T const*end()const noexcept{return data_u+size_;}
constexpr std::size_t size()const noexcept{return size_;}
};
模板
constexpr范围为_范围(T const&T)
{
返回{&t,1};
}
模板
结构A;
模板
constexpr范围作为_范围(常数A)
{
返回{a.arr,N};
}
然后,您可以简单地在所有范围的所有元素上执行双循环
template <typename T, size_t N>
struct A
{
T arr[N]; // aggregate
constexpr A() = default;
template <typename U, typename... Us>
constexpr A(U const u, Us const&... us)
:
arr{}
{
Range<T> rngs[1 + sizeof...(Us)] { as_range(u), as_range(us)... };
auto i = 0;
for (auto const& r : rngs)
for (auto const& elem : r)
arr[i++] = elem;
assert(i == N);
}
};
模板
结构A
{
T arr[N];//聚合
constexpr A()=默认值;
模板
常数表达式A(U常数U,美国常数和…美国)
:
arr{}
{
射程RNG[1+sizeof…(Us)]{as_射程(u),as_射程(Us)…};
自动i=0;
用于(自动施工和恢复:rngs)
用于(自动常量和元素:r)
arr[i++]=elem;
断言(i==N);
}
};
在编译时工作(需要GCC>=6.0或Clang>=3.4)
模板
无效打印(A常量和A){
对于(T const&T:a.arr){
std::cout在ay(1,2)中y[2]
的预期值是多少;
?构造函数调用的运行时开销如何?@VaughnCato感谢您的捕获,这是一个错误类型,已更新now@WojciechFrohmbergconstexpr意味着内联,所以我们不能谈论调用。我要添加的唯一一件事是使用forward\u as\u tuple
来减少复制更容易理解(由于没有模板元编程),“不引入任何运行时开销”规范丢失。@black,谢谢,FTFY。请注意,这需要将数据成员从std::array
更改为T[N]
C-array,因为非常量运算符[]前者的
不是constexpr
。
template<class T>
struct Range
{
T const* data_;
std::size_t size_;
constexpr T const* begin() const noexcept { return data_; }
constexpr T const* end() const noexcept { return data_ + size_; }
constexpr std::size_t size() const noexcept { return size_; }
};
template<class T>
constexpr Range<T> as_range(T const& t)
{
return { &t, 1 };
}
template<class T, std::size_t N>
struct A;
template<class T, std::size_t N>
constexpr Range<T> as_range(A<T, N> const& a)
{
return { a.arr, N };
}
template <typename T, size_t N>
struct A
{
T arr[N]; // aggregate
constexpr A() = default;
template <typename U, typename... Us>
constexpr A(U const u, Us const&... us)
:
arr{}
{
Range<T> rngs[1 + sizeof...(Us)] { as_range(u), as_range(us)... };
auto i = 0;
for (auto const& r : rngs)
for (auto const& elem : r)
arr[i++] = elem;
assert(i == N);
}
};
template <class T, size_t N>
void print(A<T, N> const& a) {
for (T const& t : a.arr) {
std::cout << t << ' ';
}
std::cout << '\n';
}
int main()
{
constexpr A<int, 3> x(1, 2, 3);
constexpr A<int, 2> y(1, 2);
constexpr A<int, 6> a(x, 1, 2, 3);
constexpr A<int, 6> b(1, x, 2, 3);
constexpr A<int, 6> c(1, 2, x, 3);
constexpr A<int, 6> d(1, 2, 3, x);
constexpr A<int, 6> e(x, x);
constexpr A<int, 6> f(y, y, y);
print(a); // 1 2 3 1 2 3
print(b); // 1 1 2 3 2 3
print(c); // 1 2 1 2 3 3
print(d); // 1 2 3 1 2 3
print(e); // 1 2 3 1 2 3
print(f); // 1 2 1 2 1 2
}