2

I have a small Slice class that I use for functions that want to take a 'list' of items. It doesn't store any items, but is just a view into some existing list.

#include <initializer_list>

template<typename T>
struct Slice
{
    u32 length;
    T*  data;

    Slice(T& element) { length = 1; data = &element; }

    template<typename T, u32 Length>
    Slice(T(&arr)[Length]) { length = Length; data = arr; }

    inline T& operator [](u32 i) { return data[i]; }
};

I'm trying to make it possible to construct from an initializer list. Like so

Slice<i32> indices = { 0, 1, 2, 2, 3, 0 };

So I tried adding a constructor that takes an initializer_list

    template<typename T>
    Slice(std::initializer_list<T> initList) { length = initList.size(); data = (T*) initList.begin(); }

But, I think this is ill-formed because the initializer_list is a temporary value that will go out of scope after the assignment. Further, the Slice data is not strictly const and it appears that initializer_lists are.

Is there a proper way to implement this behavior?

Adam
  • 1,122
  • 9
  • 21
  • 2
    Why do you want to be able to initialize the slice from an initializer list if it makes no sense? – juanchopanza Nov 07 '18 at 07:17
  • Say I have a function that takes a Slice, and I want to pass an initializer list instead of explicitly creating an array/list before the call. `void Foo(Slice bar) { ... }` then `Foo({1, 2, 3});` – Adam Nov 07 '18 at 07:27
  • Then why not disallow it by not having a `std::initializer_list` constructor? – Some programmer dude Nov 07 '18 at 07:28
  • I *want* that behavior – Adam Nov 07 '18 at 07:29
  • 4
    You can't take ownership of the initializer list's underlying array. That's a non-starter. – StoryTeller - Unslander Monica Nov 07 '18 at 07:41
  • 1
    Why not to use a variable to hold an `initializer_list`? `auto x = {1, 2, 3}; Slice indices(x);`. Then it will be a view into `x`. – Evg Nov 07 '18 at 07:47
  • That's likely true. I may have been overzealous with my title. std:array allows initializer list syntax by copying the underlying data. I'm ok with copying the data for the intializer list case, but not for the other cases where it's not necessary. – Adam Nov 07 '18 at 07:49
  • There is some proposal for movable-from `initializer_list`: http://open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4166.pdf. But its status is still _open_: https://cplusplus.github.io/EWG/ewg-status.html – Daniel Langr Nov 07 '18 at 08:26
  • Ok, so copying is definitely the way to go. Now I have to figure out if it's possible to do that without needing a separate type. Seems unlikely though. – Adam Nov 08 '18 at 05:23

1 Answers1

0

You definitely want to copy those temporaries. You can use dynamic allocation in this case and a flag to signal the ownership:

template<typename T>
struct Slice
{
private:
    u32 length;
    T*  data;
    bool owns= false;

public:
    Slice(T& element) { length = 1; data = &element; }

    template<u32 Length>
    Slice(T(&arr)[Length]) { length = Length; data = arr; }

    Slice(std::initializer_list<T> initList): length(initList.size()), owns(true)
      { data= new T[length]; std::copy(initList.begin(),initList.end(),data); }

    ~Slice() { if (owns) delete[] data; }

    inline T& operator [](u32 i) { return data[i]; }
};
metalfox
  • 6,301
  • 1
  • 21
  • 43