c++ - 如何在不硬编码数组大小的情况下在类的初始化器列表中初始化 std::array
问题描述
我有 Foo.h:
#include <array>
class Bar {
public:
Bar(std::string name) : name(name) {}
std::string name;
};
class Foo {
public:
enum {ARRAY_SIZE=10};
Foo();
void printElement(int idx);
std::array<Bar,ARRAY_SIZE> myArray;
};
Foo.cc:
#include "Foo.h"
#include <iostream>
Foo::Foo(): myArray({Bar("9"),Bar("8"),Bar("7"),Bar("6"),Bar("5"),
Bar("4"),Bar("3"),Bar("2"),Bar("1"),Bar("0")}) {}
void Foo::printElement(int idx) {
if (idx < ARRAY_SIZE) {
std::cout << "Value is " << myArray[idx].name << std::endl;
} else {
std::cout << "Index out of bounds" << std::endl;
}
}
int main() {
Foo foo;
foo.printElement(1);
}
问题是
{Bar("9"),Bar("8"),Bar("7"),Bar("6"),Bar("5"),Bar("4"),Bar("3"),Bar("2"),Bar("1"),Bar("0")}
太字面了,我需要能够使用一个表达式,该表达式根据 ARRAY_SIZE 的值(可以存在于外部头文件中)扩展到正确的大小。
请注意,在此示例中,我必须myArray
在初始化程序列表中进行初始化,否则我会得到:
(...)/gcc/6.3.0/include/c++/6.3.0/array:90:12: error: no matching function for call to 'Bar::Bar()'
最好的方法是什么?
顺便说一句,我正在使用 g++ 6.3.0。
解决方案
使用辅助函数。添加
template <std::size_t N>
auto make_array()
{
std::array<Bar, N> arr;
for (std::size_t i = 0; i < N; ++i)
arr[i] = std::to_string(N - i - 1);
return arr;
}
到您的班级,然后您可以在成员初始化程序列表中使用它,例如
Foo::Foo(): myArray(make_array<10>()) {}
这仅适用于Bar
默认可构造的情况。
对于您的代码,您可以做的是添加另一个具有 astd::index_sequence
值的助手来构造Bar
's ,这看起来像
// helpers for reversing an integer sequence
template <std::size_t ... Is>
constexpr auto indexSequenceReverse (std::index_sequence<Is...> const &)
-> decltype( std::index_sequence<sizeof...(Is)-1U-Is...>{} );
template <std::size_t N>
using makeIndexSequenceReverse
= decltype(indexSequenceReverse(std::make_index_sequence<N>{}));
class Bar {
public:
Bar(std::string name) : name(name) {}
std::string name;
};
class Foo {
public:
enum {ARRAY_SIZE=10};
Foo();
void printElement(int idx);
std::array<Bar,ARRAY_SIZE> myArray;
// get sequence and expand out initializes
template <std::size_t ... Is>
auto make_array_impl(std::integer_sequence<size_t, Is...>)
{
return std::array{ Bar{std::to_string(Is)}... };
}
// convenient forwarder to implementation
template <std::size_t N>
auto make_array()
{
return make_array_impl(makeIndexSequenceReverse<N>{});
}
};
Foo::Foo(): myArray(make_array<10>()) {}
void Foo::printElement(int idx) {
if (idx < ARRAY_SIZE) {
std::cout << "Value is " << myArray[idx].name << std::endl;
} else {
std::cout << "Index out of bounds" << std::endl;
}
}
int main() {
Foo foo;
foo.printElement(1);
}
推荐阅读
- r - Likert中的错误:所有项目(列)在R中必须具有相同数量的级别
- sql - 如何在 where 子句中指定 @filterColumn 和 @filterValue?
- f# - F# - 将一个元素附加到列表的开头
- html - iframe 网站拒绝连接,x-frame-options 被拒绝
- javascript - 你能从远程托管的 iframe 中检测字体吗?
- java - SQL Polybase 可以从 Azure datalake gen2 读取数据吗?
- javascript - Bootstrap Carousel White-Background in between Slides
- git - 将本地主分支与远程分支合并后,是否应该将其推送回远程?
- c# - 在 BizTalk 业务流程中处理 SOAP 异常
- javascript - 在这两个代码块中使用和省略关键字“await”有什么区别?