未知("模板化")类数量的初始值设定项列表
Initializer list for an unknown ("templated") amount of classes
如果我有一个类模板,其中包含一个数组,其中另一个类的类型具有未定义的字段数量(数量是模板参数(,我如何运行它们的构造函数(如果它们采用参数(?
这里有一些示例代码:
class ArrayClass
{
public:
ArrayClass() = delete;
ArrayClass(int anyParameter) {}
};
template <const int amountOfFields>
class ContainingClass
{
ArrayClass myArray[amountOfFields];
public:
ContainingClass();
};
template <const int amountOfFields>
ContainingClass<amountOfFields>::ContainingClass()
:
myArray(5) // doesn't work of cause
{}
是否可以为每个 ArrayClass(无论有多少个(提供相同的参数(或不同的参数(?(我本质上不需要它,但它会让我的事情变得更容易(
在这种情况下,C++标准库中没有任何内容
如果你使用 GCC 进行编译,它有一个称为远程初始化的专有扩展。使用 GCC,您可以编写如下内容(未经测试(:
template<size_t amountOfFields>
ContainingClass<amountOfFields>::ContainingClass():
myArray( { [0 ... (amountOfFields-1)] = 5} )
{ }
如果您使用的是任何其他编译器,则有以下选项。
正如评论者所说,将数组替换为 std::vector,它具有您需要的构造函数。但是,这将改变RAM布局,即如果你有很多容器,每个容器的元素数量很少,数组(C数组和C++std::array(会更快,因为少了一个要追逐的指针。
从 ArrayClass 的默认构造函数中删除"=delete",在构造函数中使用
std::fill
或std::fill_n
在构造初始值后设置初始值。但是,这可能会带来一些较小的运行时成本。如果你没有太多的元素,从技术上讲,你可以使用一些模板元编程来按照你想要的方式实现静态构造的数组。但是,IMO 将很难调试大量C++代码(没有编译时调试器(。
如果你的代码中有少量不同的模板参数,你可以编写一个函数,
如template<size_t N> constexpr std::array<ArrayClass,N> fill_array(int val)
专门针对您拥有的 amountOfFields 寺庙参数的不同值,并在 ContainingClass 的构造函数中调用该函数。
其他解决方案是可能的,如外部工具、宏、提升等......但我认为 2 和 4 是最合理的解决方法。
这适用于GCC 8.1/Clang 6.0和C++14,尽管我绝对不确定它是否符合标准:
class E {
public:
E() = delete;
E(int i) : i_(i) { }
operator int() const { return i_; }
private:
int i_;
};
template <typename T>
T dummy(T val, /* [[maybe_unused]] */ size_t I) { return val; }
template <typename T, size_t... I, typename U>
constexpr auto make_array_impl(U val, std::index_sequence<I...> is) {
return std::array<T, is.size()>{dummy(val, I)...};
}
template <typename T, size_t N, typename U>
constexpr auto make_array(U val) {
return make_array_impl<T>(val, std::make_index_sequence<N>{});
}
template <typename T, size_t N>
class A {
public:
A(T val) : a_{make_array<T, N>(val)} { }
void print() { for (auto e : a_) std::cout << e << std::endl; }
private:
std::array<T, N> a_;
};
int main() {
A<E, 5> a(-1);
a.print();
}
现场演示:https://wandbox.org/permlink/Db9Zpf6gUMvg4MER
更新了更通用的解决方案:
template <typename T, size_t... I, typename... Args>
constexpr auto make_array_impl(std::index_sequence<I...> is, Args&&... args) {
return std::array<T, is.size()>{ (I, T(std::forward<Args>(args)...))... };
}
template <typename T, size_t N, typename... Args>
constexpr auto make_array(Args&&... args) {
return make_array_impl<T>(std::make_index_sequence<N>{}, std::forward<Args>(args)...);
}
- Pybind11:将元组列表从Python传递到C++
- 从链接列表c++中删除一个项目
- 如何(从固定列表中)选择一个数字序列,该序列将与目标数字相加
- C++如何通过用户输入删除列表元素
- 读取文件的最后一行并输入到链接列表时出错
- 继承期间显示未知行为的子类
- 复制列表初始化的隐式转换的等级是多少
- LNK2038、MSVS2017 MAGMA的原因列表
- 不能在初始值设定项列表中将非常量表达式从类型 'int' 缩小到'unsigned long long'
- 没有为自己的结构调用列表推回方法
- 使用简单类型列表实现的指数编译时间.为什么
- C++未知长度字符串的数组,其行为类似于 Python 字符串列表
- 将参数列表未知的可变参数模板类型定义为 std::map 值类型
- 未知("模板化")类数量的初始值设定项列表
- std :: list(双重链接列表)未知运行时错误
- 构造函数初始化器列表中未知长度的数组
- 使用Boost::Spirit解析具有未知键的"键=值"列表
- 对未知大小数组的引用的列表初始化:它是否应该推断数组大小?
- 写邻接列表图时出现未知错误
- c++ Boost循环通过未知的ptree和列表属性值