[英]Initializing array in struct
Assume we have some templated struct and sometimes it's template should be an array. 假设我们有一些模板化的结构, 有时它的模板应该是一个数组。 How to initialize array in struct?
如何在struct中初始化数组?
This 这个
template<typename T>
struct A {
T x;
A(T x) : x(x) {}
};
int a[6];
A<decltype(a)> b(a);
generates error during compilation: 编译期间生成错误:
error: array initializer must be an initializer list
A(T x) : x(x) {}
^
UPD1. UPD1。 More complete code this thing is used in:
更完整的代码这个东西用于:
template<typename T>
struct A {
T x;
A(const T& x) : x(x) {}
A(const T&& x) : x(std::move(x)) {}
};
template<typename T>
A<typename std::remove_reference<T>::type> make_A(T&& a) {
return A<typename std::remove_reference<T>::type>(std::forward<T>(a));
}
auto a = make_A("abacaba");
A general solution is to provide a special constructor for arrays (enabled when T
is an array) which copies the source array to the struct's array. 一般的解决方案是为数组提供一个特殊的构造函数(当
T
是一个数组时启用),它将源数组复制到struct的数组中。 It works, but discard move semantics for arrays. 它可以工作,但丢弃数组的移动语义。
#include <iostream>
#include <type_traits>
#include <string>
#include <tuple>
template<typename T>
struct A {
using value_type = std::remove_const_t<T>;
value_type x;
template<class U=T> A(const T& src, std::enable_if_t<!std::is_array_v<U>, int> = 0) : x(src) {}
template<class U=T> A(const T&& src, std::enable_if_t<!std::is_array_v<U>, int> = 0) : x(std::move(src)) {}
template<class U=T> A(const T& src, std::enable_if_t< std::is_array_v<U>, int> = 0) { std::copy(std::begin(src), std::end(src), std::begin(x)); }
};
template<typename T>
auto make_A(T&& a)
{ return A<typename std::remove_reference_t<T>>(std::forward<T>(a)); }
int main()
{
auto a1 = make_A("the answer");
std::ignore = a1;
auto a2 = make_A(42);
std::ignore = a2;
}
If you need T
to be const
for non-arrays sometimes, an improvement would be to define value_type
as T
if T
is not an array and to std::remove_const_t<T>
otherwise. 如果有时需要
T
为非数组的const
,那么改进就是将value_type
定义为T
如果T
不是数组),否则定义为std::remove_const_t<T>
。
I suggest putting all the smarts into make_A
, converting C-arrays to std::array<>
s so that A<>
needs only work with regular types: 我建议将所有
make_A
放入make_A
,将C数组转换为std::array<>
s,以便A<>
只需要使用常规类型:
namespace detail {
template<typename T, std::size_t... Is>
constexpr std::array<T, sizeof...(Is)> to_std_array(T const* const p,
std::index_sequence<Is...>)
{
return {{p[Is]...}};
}
}
template<typename T>
A<std::decay_t<T>> make_A(T&& x) {
return {std::forward<T>(x)};
}
template<typename T, std::size_t N>
A<std::array<T, N>> make_A(T const (& x)[N]) {
return {detail::to_std_array(x, std::make_index_sequence<N>{})};
}
If you're only concerned with hardcoded C-strings in particular (as opposed to C-arrays in general), consider converting to a string_view
type rather than std::array<>
to potentially save some space. 如果您只关注硬编码的C字符串(通常与C数组相反),请考虑转换为
string_view
类型而不是std::array<>
以节省一些空间。
If it is a special behaviour you want to achieve for C-Strings exclusively, you may just add a special treatment: 如果它是您想要专门为C-Strings实现的特殊行为,您可以添加一个特殊处理:
// for all non-C-string cases
template<typename T, std::enable_if_t<!std::is_same_v<std::decay_t<T>, const char*>>* = nullptr>
A<typename std::remove_reference<T>::type> make_A(T&& a) {
return A<typename std::remove_reference<T>::type>(std::forward<T>(a));
}
// in case a C-string got passed
A<std::string> make_A(const std::string& str) {
return A<std::string>(str);
}
int main()
{
auto a = make_A("abacaba");
auto b = make_A(5);
}
With std::decay it works: 使用std :: decay它可以工作:
template<typename T>
A<typename std::decay<T>::type> make_A(T&& a) {
return A<typename std::decay<T>::type>(std::forward<T>(a));
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.