[英]Initializing array in struct
假設我們有一些模板化的結構, 有時它的模板應該是一個數組。 如何在struct中初始化數組?
這個
template<typename T>
struct A {
T x;
A(T x) : x(x) {}
};
int a[6];
A<decltype(a)> b(a);
編譯期間生成錯誤:
error: array initializer must be an initializer list
A(T x) : x(x) {}
^
UPD1。 更完整的代碼這個東西用於:
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");
一般的解決方案是為數組提供一個特殊的構造函數(當T
是一個數組時啟用),它將源數組復制到struct的數組中。 它可以工作,但丟棄數組的移動語義。
#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;
}
如果有時需要T
為非數組的const
,那么改進就是將value_type
定義為T
如果T
不是數組),否則定義為std::remove_const_t<T>
。
我建議將所有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>{})};
}
如果您只關注硬編碼的C字符串(通常與C數組相反),請考慮轉換為string_view
類型而不是std::array<>
以節省一些空間。
如果它是您想要專門為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);
}
使用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.