C++ “如何模拟C阵列初始化”;int arr[]={e1,e2,e3,…};std::array的行为?
(注意:这个问题是关于不必指定元素的数量并且仍然允许直接初始化嵌套类型。)C++ “如何模拟C阵列初始化”;int arr[]={e1,e2,e3,…};std::array的行为?,c++,arrays,templates,initialization,c++11,C++,Arrays,Templates,Initialization,C++11,(注意:这个问题是关于不必指定元素的数量并且仍然允许直接初始化嵌套类型。) 讨论C数组的剩余用法,如intarr[20]。在上,@James Kanze展示了C阵列最后的堡垒之一,它独特的初始化特性: int arr[] = { 1, 3, 3, 7, 0, 4, 2, 0, 3, 1, 4, 1, 5, 9 }; 我们不必指定元素的数量,万岁!现在,使用()中的C++11函数std::begin和std::end对其进行迭代,您甚至不需要考虑其大小 现在,有没有任何(可能是TMP)方法可以通
讨论C数组的剩余用法,如
intarr[20]代码>。在上,@James Kanze展示了C阵列最后的堡垒之一,它独特的初始化特性:
int arr[] = { 1, 3, 3, 7, 0, 4, 2, 0, 3, 1, 4, 1, 5, 9 };
我们不必指定元素的数量,万岁!现在,使用
()中的C++11函数std::begin
和std::end
对其进行迭代,您甚至不需要考虑其大小
现在,有没有任何(可能是TMP)方法可以通过std::array
实现同样的效果?允许使用宏使其看起来更漂亮。:)
编辑:根据各种答案编译的中间版本如下所示:
#include <array>
#include <utility>
template<class T, class... Tail, class Elem = typename std::decay<T>::type>
std::array<Elem,1+sizeof...(Tail)> make_array(T&& head, Tail&&... values)
{
return { std::forward<T>(head), std::forward<Tail>(values)... };
}
// in code
auto std_array = make_array(1,2,3,4,5);
#include <array>
#include <type_traits>
#include <utility>
template<typename T, typename... Ts>
constexpr std::array<std::decay_t<T>, 1 + sizeof... (Ts)>
make_array(T&& t, Ts&&... ts)
noexcept(noexcept(std::is_nothrow_constructible<
std::array<std::decay_t<T>, 1 + sizeof... (Ts)>, T&&, Ts&&...
>::value))
{
return {{std::forward<T>(t), std::forward<Ts>(ts)...}};
}
template<typename T>
constexpr std::array<std::decay<T>, 0> make_array() noexcept
{
return {};
}
auto arr = finish( make_array<T>->* 1,2,3,4,5 );
此外,初始值设定项的数量仅限于实现支持的函数和模板参数的数量。如果std::array不是一个约束,并且您有Boost,那么请查看。这与您想要的C类型数组初始化不同。但很接近。我能想到的最好的办法是:
template<class T, class... Tail>
auto make_array(T head, Tail... tail) -> std::array<T, 1 + sizeof...(Tail)>
{
std::array<T, 1 + sizeof...(Tail)> a = { head, tail ... };
return a;
}
auto a = make_array(1, 2, 3);
template <typename... T>
constexpr auto array_of(T&&... t) {
return std::array{ static_cast<std::common_type_t<T...>>(t)... };
}
模板
自动生成数组(T头、尾…尾)->std::数组
{
数组a={head,tail…};
返回a;
}
自动a=生成数组(1,2,3);
但是,这需要编译器执行NRVO,然后还跳过返回值的副本(这也是合法的,但不是必需的)。在实践中,我希望C++编译器能够优化它,使之与直接初始化一样快。 < P>我期望一个简单的<代码> MaqyReals
template<typename ret, typename... T> std::array<ret, sizeof...(T)> make_array(T&&... refs) {
// return std::array<ret, sizeof...(T)>{ { std::forward<T>(refs)... } };
return { std::forward<T>(refs)... };
}
template std::array make_array(T&&…refs){
//返回std::数组{{std::forward(refs)…};
返回{std::forward(refs)…};
}
C++11将支持(大多数?)std容器。结合以前文章中的一些想法,这里有一个甚至适用于嵌套结构的解决方案(在GCC4.6中测试):
无论哪种方式,您都需要可变的类型特征。这里是从std::is_same
(注意,衰减对于允许混合T
、T&
、T常量和等非常重要):
template struct all_same{static const bool value=false;};
模板结构完全相同
{
静态常量bool value=std::is_same::value&&all_same::value;
};
模板结构完全相同
{
静态常量布尔值=std::is_same::value;
};
模板结构全部相同{static const bool value=true;};
请注意,make_array()
通过临时副本返回,编译器(具有足够的优化标志!)可以将其视为右值或以其他方式进行优化,并且std::array
是聚合类型,因此编译器可以自由选择最佳的构造方法
最后,请注意,当make_array
设置初始值设定项时,无法避免复制/移动构造。Sostd::array x{Foo(1),Foo(2)}代码>没有复制/移动,但是autox=make_数组(Foo(1),Foo(2))当参数被转发到make_array
时,code>有两个复制/移动。我不认为您可以在这方面做得更好,因为您无法按词汇将变量初始值设定项列表传递给帮助程序并推断类型和大小——如果预处理器有一个用于变量参数的sizeof…
函数,也许可以这样做,但不能在核心语言中完成。(由@dyp提供的解决方案)
注意:需要C++14(std::index_序列
)。虽然可以在C++11中实现std::index_序列
#include <iostream>
// ---
#include <array>
#include <utility>
template <typename T>
using c_array = T[];
template<typename T, size_t N, size_t... Indices>
constexpr auto make_array(T (&&src)[N], std::index_sequence<Indices...>) {
return std::array<T, N>{{ std::move(src[Indices])... }};
}
template<typename T, size_t N>
constexpr auto make_array(T (&&src)[N]) {
return make_array(std::move(src), std::make_index_sequence<N>{});
}
// ---
struct Point { int x, y; };
std::ostream& operator<< (std::ostream& os, const Point& p) {
return os << "(" << p.x << "," << p.y << ")";
}
int main() {
auto xs = make_array(c_array<Point>{{1,2}, {3,4}, {5,6}, {7,8}});
for (auto&& x : xs) {
std::cout << x << std::endl;
}
return 0;
}
#包括
// ---
#包括
#包括
模板
使用c_数组=T[];
模板
constexpr自动生成数组(T(&&src)[N],std::index_序列){
返回std::数组{{std::move(src[index])…};
}
模板
constexpr自动生成数组(T(&&src)[N]){
返回make_数组(std::move(src),std::make_index_sequence{});
}
// ---
结构点{intx,y;};
std::ostream&operator我知道这个问题已经问了很长时间了,但我觉得现有的答案仍然有一些不足之处,所以我想提出我稍微修改的版本。以下是我认为一些现有答案缺失的要点
1.无需依赖RVO
一些答案提到,我们需要依靠RVO返回构造的数组。事实并非如此;我们可以利用它来保证不会有临时性的创造。因此,不是:
return std::array<Type, …>{values};
2.MakeMake_数组
aconstepr
函数
这允许我们创建编译时常量数组
3.无需检查所有参数的类型是否相同
首先,如果不是,编译器将发出警告或错误,因为列表初始化不允许缩小范围。其次,即使我们真的决定做我们自己的static\u assert
事情(也许是为了提供更好的错误消息),我们仍然应该比较参数的衰减类型,而不是原始类型。比如说,
volatile int a = 0;
const int& b = 1;
int&& c = 2;
auto arr = make_array<int>(a, b, c); // Will this work?
我们可能想制作一个数组
,但现有答案中的实现可能都无法做到这一点。我们可以做的是,不是返回一个std::array
,而是返回一个std::array
template<typename ret, typename... T> std::array<ret, sizeof...(T)> make_array(T&&... refs) {
// return std::array<ret, sizeof...(T)>{ { std::forward<T>(refs)... } };
return { std::forward<T>(refs)... };
}
这种方法有一个缺点:我们不能再返回cv限定值类型的数组。但大多数时候,我们都会使用常量数组,而不是像数组那样的东西。这是一个权衡,但我认为是合理的。C++17也采用了这种方法:
template< class T >
constexpr std::optional<std::decay_t<T>> make_optional( T&& value );
用法:
constexpr auto arr = make_array(make_array(1, 2),
make_array(3, 4));
static_assert(arr[1][1] == 4, "!");
创建一个数组生成器类型
它重载运算符,
以生成一个表达式模板,通过引用将每个元素链接到上一个元素
添加一个finish
free函数,该函数接受array maker并生成一个
volatile int a = 0;
const int& b = 1;
int&& c = 2;
auto arr = make_array<int>(a, b, c); // Will this work?
volatile int a = 0;
const int& b = 1;
int&& c = 2;
auto arr = make_array(a, b, c); // Will this work?
template< class T >
constexpr std::optional<std::decay_t<T>> make_optional( T&& value );
#include <array>
#include <type_traits>
#include <utility>
template<typename T, typename... Ts>
constexpr std::array<std::decay_t<T>, 1 + sizeof... (Ts)>
make_array(T&& t, Ts&&... ts)
noexcept(noexcept(std::is_nothrow_constructible<
std::array<std::decay_t<T>, 1 + sizeof... (Ts)>, T&&, Ts&&...
>::value))
{
return {{std::forward<T>(t), std::forward<Ts>(ts)...}};
}
template<typename T>
constexpr std::array<std::decay<T>, 0> make_array() noexcept
{
return {};
}
constexpr auto arr = make_array(make_array(1, 2),
make_array(3, 4));
static_assert(arr[1][1] == 4, "!");
auto arr = finish( make_array<T>->* 1,2,3,4,5 );
auto arr = finish( make_array<T>= {1}={2}={3}={4}={5} );
auto arr = finish( make_array<T>[{1}][{2}[]{3}][{4}][{5}] );
template <typename... T>
constexpr auto array_of(T&&... t) {
return std::array{ static_cast<std::common_type_t<T...>>(t)... };
}