简体   繁体   English

在struct中初始化数组

[英]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;
}

live demo 现场演示

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>{})};
}

Online Demo 在线演示

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM