Array class that will accept an braced-init-list and deduce length










5














This has been asked before, but I'm curious to see if anything has changed in newer C++ standards. Any current or future standard is acceptable.



Q: Is there anyway to create an Array class that can be initialized with a braced-init-list without having to manually specify the array length, with elements stored on the stack, and doesn't require a 'make_array' function.



template<class T, size_t N>
struct Array

T items[N];
;

Array<int> foo = 1, 2, 3 ;


Since initializer_list is not templated on the size, a constructor using it won't do the job. Deduction guides in C++17 nearly work, but you have to omit the type parameter and all items must have exactly the same type



Array foo = 1, 2, 3 ; // Works
Array<int> foo = 1, 2, 3 ; // Doesn't work
Array foo = 1.0, 2.0, 3.0f ; //Doesn't work


A constructor that takes a c-array doesn't appear to work because an initializer_list won't convert to a c-array.



Is the braced-init-list to T[N] that happens in int foo = 1, 2, 3 ; purely compiler magic that can't be replicated in code?



EDIT: The spirit of this question is about the exact syntax above. No make_array, no extra template argument, explicit item type, no double braces, no dynamic allocations. If a trivial Array requires a bunch of modern C++ tomfoolery and still can't manage to support standard syntax then it's just a bad engineering trade-off in my opinion.










share|improve this question























  • Maybe you could create something much like std::array, but force the deduction guide by using some tag type as the first constructor argument. Would look something like Array foo = Tag<int>, 1, 2, 3;. (I haven't thought this all the way through yet...)
    – BoBTFish
    Nov 8 at 8:21






  • 1




    @BoBTFish - interesting idea: should permit to explicit the type, bypassing the problem that you can't explicit a template parameter using template guides; IMHO, you should elaborate it and propose it as an answer.
    – max66
    Nov 8 at 14:12










  • I don't know what 'making it a placeholder' means. I also don't know where type ambiguity makes it into the equation. It boils down to: it should be possible to write a constructor that takes a braced-init-list and has a compile-time known size. I'm not looking to change std::array.
    – Adam
    Nov 10 at 19:37















5














This has been asked before, but I'm curious to see if anything has changed in newer C++ standards. Any current or future standard is acceptable.



Q: Is there anyway to create an Array class that can be initialized with a braced-init-list without having to manually specify the array length, with elements stored on the stack, and doesn't require a 'make_array' function.



template<class T, size_t N>
struct Array

T items[N];
;

Array<int> foo = 1, 2, 3 ;


Since initializer_list is not templated on the size, a constructor using it won't do the job. Deduction guides in C++17 nearly work, but you have to omit the type parameter and all items must have exactly the same type



Array foo = 1, 2, 3 ; // Works
Array<int> foo = 1, 2, 3 ; // Doesn't work
Array foo = 1.0, 2.0, 3.0f ; //Doesn't work


A constructor that takes a c-array doesn't appear to work because an initializer_list won't convert to a c-array.



Is the braced-init-list to T[N] that happens in int foo = 1, 2, 3 ; purely compiler magic that can't be replicated in code?



EDIT: The spirit of this question is about the exact syntax above. No make_array, no extra template argument, explicit item type, no double braces, no dynamic allocations. If a trivial Array requires a bunch of modern C++ tomfoolery and still can't manage to support standard syntax then it's just a bad engineering trade-off in my opinion.










share|improve this question























  • Maybe you could create something much like std::array, but force the deduction guide by using some tag type as the first constructor argument. Would look something like Array foo = Tag<int>, 1, 2, 3;. (I haven't thought this all the way through yet...)
    – BoBTFish
    Nov 8 at 8:21






  • 1




    @BoBTFish - interesting idea: should permit to explicit the type, bypassing the problem that you can't explicit a template parameter using template guides; IMHO, you should elaborate it and propose it as an answer.
    – max66
    Nov 8 at 14:12










  • I don't know what 'making it a placeholder' means. I also don't know where type ambiguity makes it into the equation. It boils down to: it should be possible to write a constructor that takes a braced-init-list and has a compile-time known size. I'm not looking to change std::array.
    – Adam
    Nov 10 at 19:37













5












5








5


3





This has been asked before, but I'm curious to see if anything has changed in newer C++ standards. Any current or future standard is acceptable.



Q: Is there anyway to create an Array class that can be initialized with a braced-init-list without having to manually specify the array length, with elements stored on the stack, and doesn't require a 'make_array' function.



template<class T, size_t N>
struct Array

T items[N];
;

Array<int> foo = 1, 2, 3 ;


Since initializer_list is not templated on the size, a constructor using it won't do the job. Deduction guides in C++17 nearly work, but you have to omit the type parameter and all items must have exactly the same type



Array foo = 1, 2, 3 ; // Works
Array<int> foo = 1, 2, 3 ; // Doesn't work
Array foo = 1.0, 2.0, 3.0f ; //Doesn't work


A constructor that takes a c-array doesn't appear to work because an initializer_list won't convert to a c-array.



Is the braced-init-list to T[N] that happens in int foo = 1, 2, 3 ; purely compiler magic that can't be replicated in code?



EDIT: The spirit of this question is about the exact syntax above. No make_array, no extra template argument, explicit item type, no double braces, no dynamic allocations. If a trivial Array requires a bunch of modern C++ tomfoolery and still can't manage to support standard syntax then it's just a bad engineering trade-off in my opinion.










share|improve this question















This has been asked before, but I'm curious to see if anything has changed in newer C++ standards. Any current or future standard is acceptable.



Q: Is there anyway to create an Array class that can be initialized with a braced-init-list without having to manually specify the array length, with elements stored on the stack, and doesn't require a 'make_array' function.



template<class T, size_t N>
struct Array

T items[N];
;

Array<int> foo = 1, 2, 3 ;


Since initializer_list is not templated on the size, a constructor using it won't do the job. Deduction guides in C++17 nearly work, but you have to omit the type parameter and all items must have exactly the same type



Array foo = 1, 2, 3 ; // Works
Array<int> foo = 1, 2, 3 ; // Doesn't work
Array foo = 1.0, 2.0, 3.0f ; //Doesn't work


A constructor that takes a c-array doesn't appear to work because an initializer_list won't convert to a c-array.



Is the braced-init-list to T[N] that happens in int foo = 1, 2, 3 ; purely compiler magic that can't be replicated in code?



EDIT: The spirit of this question is about the exact syntax above. No make_array, no extra template argument, explicit item type, no double braces, no dynamic allocations. If a trivial Array requires a bunch of modern C++ tomfoolery and still can't manage to support standard syntax then it's just a bad engineering trade-off in my opinion.







c++ c++17 initializer-list template-deduction c++20






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 10 at 19:12

























asked Nov 8 at 8:09









Adam

206513




206513











  • Maybe you could create something much like std::array, but force the deduction guide by using some tag type as the first constructor argument. Would look something like Array foo = Tag<int>, 1, 2, 3;. (I haven't thought this all the way through yet...)
    – BoBTFish
    Nov 8 at 8:21






  • 1




    @BoBTFish - interesting idea: should permit to explicit the type, bypassing the problem that you can't explicit a template parameter using template guides; IMHO, you should elaborate it and propose it as an answer.
    – max66
    Nov 8 at 14:12










  • I don't know what 'making it a placeholder' means. I also don't know where type ambiguity makes it into the equation. It boils down to: it should be possible to write a constructor that takes a braced-init-list and has a compile-time known size. I'm not looking to change std::array.
    – Adam
    Nov 10 at 19:37
















  • Maybe you could create something much like std::array, but force the deduction guide by using some tag type as the first constructor argument. Would look something like Array foo = Tag<int>, 1, 2, 3;. (I haven't thought this all the way through yet...)
    – BoBTFish
    Nov 8 at 8:21






  • 1




    @BoBTFish - interesting idea: should permit to explicit the type, bypassing the problem that you can't explicit a template parameter using template guides; IMHO, you should elaborate it and propose it as an answer.
    – max66
    Nov 8 at 14:12










  • I don't know what 'making it a placeholder' means. I also don't know where type ambiguity makes it into the equation. It boils down to: it should be possible to write a constructor that takes a braced-init-list and has a compile-time known size. I'm not looking to change std::array.
    – Adam
    Nov 10 at 19:37















Maybe you could create something much like std::array, but force the deduction guide by using some tag type as the first constructor argument. Would look something like Array foo = Tag<int>, 1, 2, 3;. (I haven't thought this all the way through yet...)
– BoBTFish
Nov 8 at 8:21




Maybe you could create something much like std::array, but force the deduction guide by using some tag type as the first constructor argument. Would look something like Array foo = Tag<int>, 1, 2, 3;. (I haven't thought this all the way through yet...)
– BoBTFish
Nov 8 at 8:21




1




1




@BoBTFish - interesting idea: should permit to explicit the type, bypassing the problem that you can't explicit a template parameter using template guides; IMHO, you should elaborate it and propose it as an answer.
– max66
Nov 8 at 14:12




@BoBTFish - interesting idea: should permit to explicit the type, bypassing the problem that you can't explicit a template parameter using template guides; IMHO, you should elaborate it and propose it as an answer.
– max66
Nov 8 at 14:12












I don't know what 'making it a placeholder' means. I also don't know where type ambiguity makes it into the equation. It boils down to: it should be possible to write a constructor that takes a braced-init-list and has a compile-time known size. I'm not looking to change std::array.
– Adam
Nov 10 at 19:37




I don't know what 'making it a placeholder' means. I also don't know where type ambiguity makes it into the equation. It boils down to: it should be possible to write a constructor that takes a braced-init-list and has a compile-time known size. I'm not looking to change std::array.
– Adam
Nov 10 at 19:37












5 Answers
5






active

oldest

votes


















6














You can work around the need for all the types in the list to be the same by using an explicit deduction guide:



template <class... T>
Array(T&&... t) -> Array<std::common_type_t<T...>, sizeof...(T)>;

Array foo = 1.0, 2.0, 3.0f ; // Deduces Array<double,3u>





share|improve this answer






















  • This is the closest I've seen to an answer, falling short only in that the array size is not part of the template.
    – Steven W. Klassen
    Nov 9 at 8:09










  • @StevenW.Klassen It is a part of the template (a second template parameter). Template parameters of the deduction guide don't match template parameters of the class here.
    – HolyBlackCat
    Nov 10 at 9:56


















5














I hate to be the bearer of bad news, but I believe that at the current time (at least as of C++17) the answer to your question is "no" there is no way that would meet all of your given requirements. That said, there are solutions posted here that come close, but they all fall short in one or more of your requirements.



I also suspect that the answer will remain "no" in the near future. Not that I'm a prophet, but the direction of the last few C++ versions would seem to imply that a make_array solution is more likely to be what is added rather than more direct language support.



Explanation



Allow me to explain why in a little more detail.



First consider the C++17 deduction guides. I won't go into detail on them as they are discussed suitably by other answers on this question. They do come very close to what you are asking but do seem to fall short in one way or the other. (Although the answer by @max66 would seem to meet all your requirements except for the extra brackets. If his syntax in fact works you may want to consider that answer as "close enough".)



Next consider a variatic templates solution. In order to automatically determine N you would need a series of overloaded functions (basically one with a single argument and one that takes a single argument and the rest of the variatic templates). But that would essentially be equivalent to some form of make_array so it doesn't count either.



Finally, the only other option I could see would be based on an initializer_list. The question is how to determine N from that list. In C++11 this would be obviously impossible since the only access to the size of the list is const and not constexpr. However as of C++14 the size() method is in fact constexpr so you would think it is at least theoretically possible to get the compiler to deduce N based on that. Unfortunately to do this you would need to make N (a template parameter) default to a value of something in the class constructor (the initializer list). I have been unable to determine any means of doing this in the present form of the language.



How I think a future version could support this



One way to support this would be to follow the examples of other languages and add direct language support, bridging a syntax to certain classes. But this essentially makes some classes "special". Consider the following line in Swift:



let ar = [1, 2, 3, 4]


In this example ar is an object of the type Array<Int>. But this is done by direct compiler support, i.e. "Array" is a special case. No matter what you do you could not write a MyArray class that would perform the same way (other than perhaps having MyArray accept an Array as a construction option). It is certainly possible for the C++ standard to be extended to do something similar, but C++ tends to try to avoid those "special" cases. Besides, an argument could be made that



auto ar = make_array(1, 2, 3, 4);


is in fact a clearer representation of the intent than would be something like the following: (suggesting the character 'A' to distinguish this from an initializer list)



auto ar = A 1, 2, 3, 4 ;


Another way, more in line with current C++ syntax, to do this would be to add the N parameter to the initializer_list template class. After all since size() is now constexpr the size must be known at compile time, so why not make it available as a template parameter? It could suitably default so that it could rarely be needed, but it would allow classes (both standard ones like std::array and custom ones like you are proposing) the possibility of tying the N in the Array template to the N in the initializer_list. Then you should be able to write something along the following lines:



template<class T, size_t N>
struct Array

explicit Array(std::initializer_list<N> il);



Of course the trick would be to make this initializer_list change in a fashion that does not break a lot of existing code.



I suspect the standards committee will not follow either of these paths, but will more likely add the experimental make_array method. And I'm not convinced that is a bad idea. We are used to make_... in many other parts of the language, so why not here as well?






share|improve this answer


















  • 1




    My answer isn’t make_array, my answer is no there isn’t at the current time. The experimental make_array may be an indication that something is perhaps being considered.
    – Steven W. Klassen
    Nov 8 at 18:41










  • That said, there are some techniques being listed here that could yet prove me wrong. (Perhaps the answer is not ‘no’.)
    – Steven W. Klassen
    Nov 8 at 18:43






  • 1




    This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. - From Review
    – Ken Y-N
    Nov 8 at 23:48






  • 1




    The reviewers have a divided opinion of my post with half saying delete and half saying it is ok. Before going the delete route, I'm going to rephrase my answer and explain in more detail why I believe the correct answer is in fact (and unfortunately) "no".
    – Steven W. Klassen
    Nov 9 at 8:02


















1














Here's one approach that allows you to specify the type. We use an extra argument to specify the type, so that we can still use the deduction guide to pick up the size. I don't consider it pretty though:



#include <iostream>

template <typename T>
struct Tag ;

template <typename T, size_t N>
struct Array
T data_[N];

template <typename... U>
Array(Tag<T>, U... u)
: data_static_cast<T>(u)... // cast to shut up narrowing conversions - bad idea??

;

template <typename T, typename... U>
Array(Tag<T>, U...) -> Array<T, sizeof...(U)>;

int main()

Array aTag<double>, 1, 2.0f, 3.0;
for (auto d : a.data_)
std::cout << d << 'n';




This is clearly not a full implementation of such a class, just to illustrate the technique.






share|improve this answer


















  • 1




    Nice; I suggest to add, a SFINAE enable check in template signature (something as template <typename ... U, typename = std::enable_if_t<N == sizeof...(U)>> (or maybe is enough sizeof...(U) <= N) to avoid that someone can write something as Array<int, 2> aTag<int>, 1, 2, 3;
    – max66
    Nov 8 at 15:07


















1















Deduction guides in C++17 nearly work, but you have to omit the type parameter and all items must have exactly the same type




Not necessarily.



Yes, you can't explicit the type parameter, but you can decide it according the types of the items.



I imagine two reasonable strategies: (1) the type of the Array is the type of the first item, following the std::array way, so writing the following deduction guide



template <typename T, typename ... Us>
Array(T, Us...) -> Array<T, 1u + sizeof...(Us)>;


(but observe that a C++ program where a Us type is different from T, for a std::array, is ill formed) or (2) follows the metalfox's suggestion and select the item's common type



template <typename ... Ts>
Array(Ts...) -> Array<std::common_type_t<Ts...>, sizeof...(Ts)>;



Is the braced-init-list to T[N] that happens in int foo = 1, 2, 3 ; purely compiler magic that can't be replicated in code?




Are you thinking in a deduction guide as follows ?



template <typename T, std::size_t N>
Array(T const (&)[N]) -> Array<T, N>;


Works but with a couple of drawbacks: (1) you have to add a couple of brackets using it



// added ---V V--- added
Array foo1 = 1, 2, 3 ; // Works


and (2) remain the problem that all items must have the same type



Array foo2 = 1.0, 2.0, 3.0f ; //Doesn't work: incompatible types


or the compiler can't deduce the type T



P.s.: what's wrong with a make_array() function ?



P.s.2: I suggest to give a look at BoBTFish's answer to see a nice method to bypass the impossibility to explicit a template argument using deduction guides.






share|improve this answer






























    0














    You had asked this:




    Q: Is there anyway to create an Array class that can be initialized with a braced-init-list without having to manually specify the array length, and without a 'make_array' function.




    I have worked on an implementation of a class that behaves in the manner you are describing only it has a little bit more complexity to it but still fairly simple, readable, reusable, portable and generic.



    I was not able to have a T items array as a direct member in the class. I had to use a T* items instead and create an overloaded operator in the derived class to mimic the behavior of an array. This doesn't mean that there isn't any work around to this as others have shown. I just find that this is one possible solution without having to specify the size of the array.



    I use a base class to store the elements from the constructor either by means of an std::initializer_list or of a variadic constructor. The class templates themselves are not a variadic template only their constructor's are. The base class stores the values from the initializer_list or parameter pack into an std::vector. The inherited class stores the contents from the vector into T* by calling the data() function of the vector class.



    template<typename T>
    class ParamPack
    protected:
    std::vector<T> values_;
    size_t size_;
    public:
    template<typename... U>
    ParamPack( U... u ) :
    values_ static_cast<T>(u)... ,
    size_( sizeof...(U) )

    template<typename ... U>
    ParamPack( std::initializer_list<std::is_same<T, U...>( U...)> il ) :
    values_( il ), size_( il.size() )

    std::vector<T>& operator()() return values_;

    size_t size() const return size_;
    ;

    template<typename T>
    class Array : public ParamPack<T>
    private:
    T* items_;
    public:
    template<typename... U>
    Array( U... u ) : ParamPack<T>::ParamPack( u... )
    items_ = this->values_.data();


    template<typename... U>
    Array( std::initializer_list<U...> il ) : ParamPack<T>::ParamPack( il )
    items_ = this->values_.data();


    T& operator( size_t idx )
    return items_[idx];


    T operator( size_t idx ) const
    return items_[idx];


    T* data() const return items_;
    ;

    int main()
    try
    // Parameter Pack Examples:
    // Variadic Constructor ...
    std::cout << "ParamPack<T> Examples:n";
    std::cout << "Using ParamPack<T>'s Variadic Constructorn";
    ParamPack<int> pp1( 1, 2, 3, 4 );
    std::cout << "Size: " << pp1.size() << " catch( const std::runtime_error& e )
    std::cerr << e.what() << 'n';
    return EXIT_FAILURE;


    return EXIT_SUCCESS;



    -Output-



    ParamPack<T> Examples:
    Using ParamPack<T>'s Variadic Constructor
    Size: 4 | Elements: 1 2 3 4
    Using ParamPack<T>'s Variadic Constructor with an Initializer List
    Size: 4 | Elements: 5 6 7 8
    Using ParamPack<T>'s initializer_list Constructor
    Size: 4 | Elements: 9 10 11 12

    Array<T> Examples:
    Using Array<T>'s initializer_list Constructor
    9 10 12 12

    Using Array<T>'s Variadic Constructor
    9 8 7 6
    Hello World

    Using Array<T>'s Constructor with Initializer List
    105 210 420

    Using Array<T>'s Initializer List with =
    1 2 3 4
    a b c d
    1.2 3.4 5.6 7.8

    Using Array<T>'s Initializer List directly
    3 6 9 12

    Using Array<T>'s Variadic Constructor with user data type
    (1,2) (3,4) (5,6)
    Using Array<T>'s Variadic Constructor With Initializer List of user data type
    (5,6) (3,4) (1,2)
    Using Array<T>'s = Initializer List with user data type
    (3,4) (1,2) (5,6)
    Using Array<T>'s Initializer List directly with user data type
    (3,4) (5,6) (1,2)
    Using Array<T>'s initializer_list Constructor with user data type

    Using Array<T>'s base class's operator()() to retrieve vector
    (3,4) (5,6) (1,2)
    Using Array<T>'s data() to get the contents of its internal pointer
    (3,4) (5,6) (1,2)


    Now this is a little more robust as it has operators that are available from both the parent and child class, from the parent class you can get the stored vector directly from its operator()(). From the child class you can index into the child's stored pointer from operator() and there is a function to return it's size. The template itself does not contain a size_t N template argument since the size is stored internally in the base class and is determined by the size of its vector. With this I'm treating T* p as if it was T p[size]. This class is still not without some limitations.



    -Valid Construction-



    Array<int> a( 1, 2, 3, 4 ); // Variadic Constructor Okay
    Array<int> a( 1,2,3,4 ); // Initializer List Constructor Okay
    Array<int> a = 1, 2, 3, 4 ; // Initializer List Okay
    Array<int> a 1,2,3,4 ; // Initializer List Okay


    -Limitations-



    However you have to explicitly instantiate the template as these will not work as they all generate a compiler error.



    Array a( 1,2,3,4 );
    Array a( 1,2,3,4 );
    Array a = 1, 2, 3, 4 ;
    Array a 1,2,3,4 ;


    -Note- There maybe more that can be done to make this more efficient, maybe even thread safe or exception safe, but this is just a generalization of the class design.




    Please let me know what you think about this:






    share|improve this answer






















    • I appreciate your thoroughness. However, this answer boils down to 'allocate and copy elements into a vector' and it's needlessly complex even for that case. The defining features of an array are no dynamic allocation and a compile time known size.
      – Adam
      Nov 10 at 19:28










    • @Adam I know, but the problem with trying to not specific the array's size by inferring it from the amount of the parameters passed into the initializer list's constructor will not work because the size of the array has to be known at compile time. Even though you are calling the constructor on the class, the compiler has to set aside memory for the class and all of its members before it can call its ctor and thus it can not create the array without knowing how many elements of type T to reserve for the class's construction.
      – Francis Cugler
      Nov 11 at 7:10










    • @Adam also your question is a very good question. I posted this answer because I enjoyed the attempt at trying to mimic a C arrays behavior. There are no direct issues with the code above, maybe some room for efficiency, but in the output section I'm kind of wording some of it wrong. Non of the examples are using the 2nd constructor of the two classes. They are all using the 1st constructor which is the variadic version. I'm working on it now to update the main and it's output to make it more clear.
      – Francis Cugler
      Nov 11 at 7:12










    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53203629%2farray-class-that-will-accept-an-braced-init-list-and-deduce-length%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    5 Answers
    5






    active

    oldest

    votes








    5 Answers
    5






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    6














    You can work around the need for all the types in the list to be the same by using an explicit deduction guide:



    template <class... T>
    Array(T&&... t) -> Array<std::common_type_t<T...>, sizeof...(T)>;

    Array foo = 1.0, 2.0, 3.0f ; // Deduces Array<double,3u>





    share|improve this answer






















    • This is the closest I've seen to an answer, falling short only in that the array size is not part of the template.
      – Steven W. Klassen
      Nov 9 at 8:09










    • @StevenW.Klassen It is a part of the template (a second template parameter). Template parameters of the deduction guide don't match template parameters of the class here.
      – HolyBlackCat
      Nov 10 at 9:56















    6














    You can work around the need for all the types in the list to be the same by using an explicit deduction guide:



    template <class... T>
    Array(T&&... t) -> Array<std::common_type_t<T...>, sizeof...(T)>;

    Array foo = 1.0, 2.0, 3.0f ; // Deduces Array<double,3u>





    share|improve this answer






















    • This is the closest I've seen to an answer, falling short only in that the array size is not part of the template.
      – Steven W. Klassen
      Nov 9 at 8:09










    • @StevenW.Klassen It is a part of the template (a second template parameter). Template parameters of the deduction guide don't match template parameters of the class here.
      – HolyBlackCat
      Nov 10 at 9:56













    6












    6








    6






    You can work around the need for all the types in the list to be the same by using an explicit deduction guide:



    template <class... T>
    Array(T&&... t) -> Array<std::common_type_t<T...>, sizeof...(T)>;

    Array foo = 1.0, 2.0, 3.0f ; // Deduces Array<double,3u>





    share|improve this answer














    You can work around the need for all the types in the list to be the same by using an explicit deduction guide:



    template <class... T>
    Array(T&&... t) -> Array<std::common_type_t<T...>, sizeof...(T)>;

    Array foo = 1.0, 2.0, 3.0f ; // Deduces Array<double,3u>






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 8 at 13:55

























    answered Nov 8 at 10:21









    metalfox

    1,680417




    1,680417











    • This is the closest I've seen to an answer, falling short only in that the array size is not part of the template.
      – Steven W. Klassen
      Nov 9 at 8:09










    • @StevenW.Klassen It is a part of the template (a second template parameter). Template parameters of the deduction guide don't match template parameters of the class here.
      – HolyBlackCat
      Nov 10 at 9:56
















    • This is the closest I've seen to an answer, falling short only in that the array size is not part of the template.
      – Steven W. Klassen
      Nov 9 at 8:09










    • @StevenW.Klassen It is a part of the template (a second template parameter). Template parameters of the deduction guide don't match template parameters of the class here.
      – HolyBlackCat
      Nov 10 at 9:56















    This is the closest I've seen to an answer, falling short only in that the array size is not part of the template.
    – Steven W. Klassen
    Nov 9 at 8:09




    This is the closest I've seen to an answer, falling short only in that the array size is not part of the template.
    – Steven W. Klassen
    Nov 9 at 8:09












    @StevenW.Klassen It is a part of the template (a second template parameter). Template parameters of the deduction guide don't match template parameters of the class here.
    – HolyBlackCat
    Nov 10 at 9:56




    @StevenW.Klassen It is a part of the template (a second template parameter). Template parameters of the deduction guide don't match template parameters of the class here.
    – HolyBlackCat
    Nov 10 at 9:56













    5














    I hate to be the bearer of bad news, but I believe that at the current time (at least as of C++17) the answer to your question is "no" there is no way that would meet all of your given requirements. That said, there are solutions posted here that come close, but they all fall short in one or more of your requirements.



    I also suspect that the answer will remain "no" in the near future. Not that I'm a prophet, but the direction of the last few C++ versions would seem to imply that a make_array solution is more likely to be what is added rather than more direct language support.



    Explanation



    Allow me to explain why in a little more detail.



    First consider the C++17 deduction guides. I won't go into detail on them as they are discussed suitably by other answers on this question. They do come very close to what you are asking but do seem to fall short in one way or the other. (Although the answer by @max66 would seem to meet all your requirements except for the extra brackets. If his syntax in fact works you may want to consider that answer as "close enough".)



    Next consider a variatic templates solution. In order to automatically determine N you would need a series of overloaded functions (basically one with a single argument and one that takes a single argument and the rest of the variatic templates). But that would essentially be equivalent to some form of make_array so it doesn't count either.



    Finally, the only other option I could see would be based on an initializer_list. The question is how to determine N from that list. In C++11 this would be obviously impossible since the only access to the size of the list is const and not constexpr. However as of C++14 the size() method is in fact constexpr so you would think it is at least theoretically possible to get the compiler to deduce N based on that. Unfortunately to do this you would need to make N (a template parameter) default to a value of something in the class constructor (the initializer list). I have been unable to determine any means of doing this in the present form of the language.



    How I think a future version could support this



    One way to support this would be to follow the examples of other languages and add direct language support, bridging a syntax to certain classes. But this essentially makes some classes "special". Consider the following line in Swift:



    let ar = [1, 2, 3, 4]


    In this example ar is an object of the type Array<Int>. But this is done by direct compiler support, i.e. "Array" is a special case. No matter what you do you could not write a MyArray class that would perform the same way (other than perhaps having MyArray accept an Array as a construction option). It is certainly possible for the C++ standard to be extended to do something similar, but C++ tends to try to avoid those "special" cases. Besides, an argument could be made that



    auto ar = make_array(1, 2, 3, 4);


    is in fact a clearer representation of the intent than would be something like the following: (suggesting the character 'A' to distinguish this from an initializer list)



    auto ar = A 1, 2, 3, 4 ;


    Another way, more in line with current C++ syntax, to do this would be to add the N parameter to the initializer_list template class. After all since size() is now constexpr the size must be known at compile time, so why not make it available as a template parameter? It could suitably default so that it could rarely be needed, but it would allow classes (both standard ones like std::array and custom ones like you are proposing) the possibility of tying the N in the Array template to the N in the initializer_list. Then you should be able to write something along the following lines:



    template<class T, size_t N>
    struct Array

    explicit Array(std::initializer_list<N> il);



    Of course the trick would be to make this initializer_list change in a fashion that does not break a lot of existing code.



    I suspect the standards committee will not follow either of these paths, but will more likely add the experimental make_array method. And I'm not convinced that is a bad idea. We are used to make_... in many other parts of the language, so why not here as well?






    share|improve this answer


















    • 1




      My answer isn’t make_array, my answer is no there isn’t at the current time. The experimental make_array may be an indication that something is perhaps being considered.
      – Steven W. Klassen
      Nov 8 at 18:41










    • That said, there are some techniques being listed here that could yet prove me wrong. (Perhaps the answer is not ‘no’.)
      – Steven W. Klassen
      Nov 8 at 18:43






    • 1




      This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. - From Review
      – Ken Y-N
      Nov 8 at 23:48






    • 1




      The reviewers have a divided opinion of my post with half saying delete and half saying it is ok. Before going the delete route, I'm going to rephrase my answer and explain in more detail why I believe the correct answer is in fact (and unfortunately) "no".
      – Steven W. Klassen
      Nov 9 at 8:02















    5














    I hate to be the bearer of bad news, but I believe that at the current time (at least as of C++17) the answer to your question is "no" there is no way that would meet all of your given requirements. That said, there are solutions posted here that come close, but they all fall short in one or more of your requirements.



    I also suspect that the answer will remain "no" in the near future. Not that I'm a prophet, but the direction of the last few C++ versions would seem to imply that a make_array solution is more likely to be what is added rather than more direct language support.



    Explanation



    Allow me to explain why in a little more detail.



    First consider the C++17 deduction guides. I won't go into detail on them as they are discussed suitably by other answers on this question. They do come very close to what you are asking but do seem to fall short in one way or the other. (Although the answer by @max66 would seem to meet all your requirements except for the extra brackets. If his syntax in fact works you may want to consider that answer as "close enough".)



    Next consider a variatic templates solution. In order to automatically determine N you would need a series of overloaded functions (basically one with a single argument and one that takes a single argument and the rest of the variatic templates). But that would essentially be equivalent to some form of make_array so it doesn't count either.



    Finally, the only other option I could see would be based on an initializer_list. The question is how to determine N from that list. In C++11 this would be obviously impossible since the only access to the size of the list is const and not constexpr. However as of C++14 the size() method is in fact constexpr so you would think it is at least theoretically possible to get the compiler to deduce N based on that. Unfortunately to do this you would need to make N (a template parameter) default to a value of something in the class constructor (the initializer list). I have been unable to determine any means of doing this in the present form of the language.



    How I think a future version could support this



    One way to support this would be to follow the examples of other languages and add direct language support, bridging a syntax to certain classes. But this essentially makes some classes "special". Consider the following line in Swift:



    let ar = [1, 2, 3, 4]


    In this example ar is an object of the type Array<Int>. But this is done by direct compiler support, i.e. "Array" is a special case. No matter what you do you could not write a MyArray class that would perform the same way (other than perhaps having MyArray accept an Array as a construction option). It is certainly possible for the C++ standard to be extended to do something similar, but C++ tends to try to avoid those "special" cases. Besides, an argument could be made that



    auto ar = make_array(1, 2, 3, 4);


    is in fact a clearer representation of the intent than would be something like the following: (suggesting the character 'A' to distinguish this from an initializer list)



    auto ar = A 1, 2, 3, 4 ;


    Another way, more in line with current C++ syntax, to do this would be to add the N parameter to the initializer_list template class. After all since size() is now constexpr the size must be known at compile time, so why not make it available as a template parameter? It could suitably default so that it could rarely be needed, but it would allow classes (both standard ones like std::array and custom ones like you are proposing) the possibility of tying the N in the Array template to the N in the initializer_list. Then you should be able to write something along the following lines:



    template<class T, size_t N>
    struct Array

    explicit Array(std::initializer_list<N> il);



    Of course the trick would be to make this initializer_list change in a fashion that does not break a lot of existing code.



    I suspect the standards committee will not follow either of these paths, but will more likely add the experimental make_array method. And I'm not convinced that is a bad idea. We are used to make_... in many other parts of the language, so why not here as well?






    share|improve this answer


















    • 1




      My answer isn’t make_array, my answer is no there isn’t at the current time. The experimental make_array may be an indication that something is perhaps being considered.
      – Steven W. Klassen
      Nov 8 at 18:41










    • That said, there are some techniques being listed here that could yet prove me wrong. (Perhaps the answer is not ‘no’.)
      – Steven W. Klassen
      Nov 8 at 18:43






    • 1




      This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. - From Review
      – Ken Y-N
      Nov 8 at 23:48






    • 1




      The reviewers have a divided opinion of my post with half saying delete and half saying it is ok. Before going the delete route, I'm going to rephrase my answer and explain in more detail why I believe the correct answer is in fact (and unfortunately) "no".
      – Steven W. Klassen
      Nov 9 at 8:02













    5












    5








    5






    I hate to be the bearer of bad news, but I believe that at the current time (at least as of C++17) the answer to your question is "no" there is no way that would meet all of your given requirements. That said, there are solutions posted here that come close, but they all fall short in one or more of your requirements.



    I also suspect that the answer will remain "no" in the near future. Not that I'm a prophet, but the direction of the last few C++ versions would seem to imply that a make_array solution is more likely to be what is added rather than more direct language support.



    Explanation



    Allow me to explain why in a little more detail.



    First consider the C++17 deduction guides. I won't go into detail on them as they are discussed suitably by other answers on this question. They do come very close to what you are asking but do seem to fall short in one way or the other. (Although the answer by @max66 would seem to meet all your requirements except for the extra brackets. If his syntax in fact works you may want to consider that answer as "close enough".)



    Next consider a variatic templates solution. In order to automatically determine N you would need a series of overloaded functions (basically one with a single argument and one that takes a single argument and the rest of the variatic templates). But that would essentially be equivalent to some form of make_array so it doesn't count either.



    Finally, the only other option I could see would be based on an initializer_list. The question is how to determine N from that list. In C++11 this would be obviously impossible since the only access to the size of the list is const and not constexpr. However as of C++14 the size() method is in fact constexpr so you would think it is at least theoretically possible to get the compiler to deduce N based on that. Unfortunately to do this you would need to make N (a template parameter) default to a value of something in the class constructor (the initializer list). I have been unable to determine any means of doing this in the present form of the language.



    How I think a future version could support this



    One way to support this would be to follow the examples of other languages and add direct language support, bridging a syntax to certain classes. But this essentially makes some classes "special". Consider the following line in Swift:



    let ar = [1, 2, 3, 4]


    In this example ar is an object of the type Array<Int>. But this is done by direct compiler support, i.e. "Array" is a special case. No matter what you do you could not write a MyArray class that would perform the same way (other than perhaps having MyArray accept an Array as a construction option). It is certainly possible for the C++ standard to be extended to do something similar, but C++ tends to try to avoid those "special" cases. Besides, an argument could be made that



    auto ar = make_array(1, 2, 3, 4);


    is in fact a clearer representation of the intent than would be something like the following: (suggesting the character 'A' to distinguish this from an initializer list)



    auto ar = A 1, 2, 3, 4 ;


    Another way, more in line with current C++ syntax, to do this would be to add the N parameter to the initializer_list template class. After all since size() is now constexpr the size must be known at compile time, so why not make it available as a template parameter? It could suitably default so that it could rarely be needed, but it would allow classes (both standard ones like std::array and custom ones like you are proposing) the possibility of tying the N in the Array template to the N in the initializer_list. Then you should be able to write something along the following lines:



    template<class T, size_t N>
    struct Array

    explicit Array(std::initializer_list<N> il);



    Of course the trick would be to make this initializer_list change in a fashion that does not break a lot of existing code.



    I suspect the standards committee will not follow either of these paths, but will more likely add the experimental make_array method. And I'm not convinced that is a bad idea. We are used to make_... in many other parts of the language, so why not here as well?






    share|improve this answer














    I hate to be the bearer of bad news, but I believe that at the current time (at least as of C++17) the answer to your question is "no" there is no way that would meet all of your given requirements. That said, there are solutions posted here that come close, but they all fall short in one or more of your requirements.



    I also suspect that the answer will remain "no" in the near future. Not that I'm a prophet, but the direction of the last few C++ versions would seem to imply that a make_array solution is more likely to be what is added rather than more direct language support.



    Explanation



    Allow me to explain why in a little more detail.



    First consider the C++17 deduction guides. I won't go into detail on them as they are discussed suitably by other answers on this question. They do come very close to what you are asking but do seem to fall short in one way or the other. (Although the answer by @max66 would seem to meet all your requirements except for the extra brackets. If his syntax in fact works you may want to consider that answer as "close enough".)



    Next consider a variatic templates solution. In order to automatically determine N you would need a series of overloaded functions (basically one with a single argument and one that takes a single argument and the rest of the variatic templates). But that would essentially be equivalent to some form of make_array so it doesn't count either.



    Finally, the only other option I could see would be based on an initializer_list. The question is how to determine N from that list. In C++11 this would be obviously impossible since the only access to the size of the list is const and not constexpr. However as of C++14 the size() method is in fact constexpr so you would think it is at least theoretically possible to get the compiler to deduce N based on that. Unfortunately to do this you would need to make N (a template parameter) default to a value of something in the class constructor (the initializer list). I have been unable to determine any means of doing this in the present form of the language.



    How I think a future version could support this



    One way to support this would be to follow the examples of other languages and add direct language support, bridging a syntax to certain classes. But this essentially makes some classes "special". Consider the following line in Swift:



    let ar = [1, 2, 3, 4]


    In this example ar is an object of the type Array<Int>. But this is done by direct compiler support, i.e. "Array" is a special case. No matter what you do you could not write a MyArray class that would perform the same way (other than perhaps having MyArray accept an Array as a construction option). It is certainly possible for the C++ standard to be extended to do something similar, but C++ tends to try to avoid those "special" cases. Besides, an argument could be made that



    auto ar = make_array(1, 2, 3, 4);


    is in fact a clearer representation of the intent than would be something like the following: (suggesting the character 'A' to distinguish this from an initializer list)



    auto ar = A 1, 2, 3, 4 ;


    Another way, more in line with current C++ syntax, to do this would be to add the N parameter to the initializer_list template class. After all since size() is now constexpr the size must be known at compile time, so why not make it available as a template parameter? It could suitably default so that it could rarely be needed, but it would allow classes (both standard ones like std::array and custom ones like you are proposing) the possibility of tying the N in the Array template to the N in the initializer_list. Then you should be able to write something along the following lines:



    template<class T, size_t N>
    struct Array

    explicit Array(std::initializer_list<N> il);



    Of course the trick would be to make this initializer_list change in a fashion that does not break a lot of existing code.



    I suspect the standards committee will not follow either of these paths, but will more likely add the experimental make_array method. And I'm not convinced that is a bad idea. We are used to make_... in many other parts of the language, so why not here as well?







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 9 at 9:01

























    answered Nov 8 at 8:23









    Steven W. Klassen

    24418




    24418







    • 1




      My answer isn’t make_array, my answer is no there isn’t at the current time. The experimental make_array may be an indication that something is perhaps being considered.
      – Steven W. Klassen
      Nov 8 at 18:41










    • That said, there are some techniques being listed here that could yet prove me wrong. (Perhaps the answer is not ‘no’.)
      – Steven W. Klassen
      Nov 8 at 18:43






    • 1




      This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. - From Review
      – Ken Y-N
      Nov 8 at 23:48






    • 1




      The reviewers have a divided opinion of my post with half saying delete and half saying it is ok. Before going the delete route, I'm going to rephrase my answer and explain in more detail why I believe the correct answer is in fact (and unfortunately) "no".
      – Steven W. Klassen
      Nov 9 at 8:02












    • 1




      My answer isn’t make_array, my answer is no there isn’t at the current time. The experimental make_array may be an indication that something is perhaps being considered.
      – Steven W. Klassen
      Nov 8 at 18:41










    • That said, there are some techniques being listed here that could yet prove me wrong. (Perhaps the answer is not ‘no’.)
      – Steven W. Klassen
      Nov 8 at 18:43






    • 1




      This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. - From Review
      – Ken Y-N
      Nov 8 at 23:48






    • 1




      The reviewers have a divided opinion of my post with half saying delete and half saying it is ok. Before going the delete route, I'm going to rephrase my answer and explain in more detail why I believe the correct answer is in fact (and unfortunately) "no".
      – Steven W. Klassen
      Nov 9 at 8:02







    1




    1




    My answer isn’t make_array, my answer is no there isn’t at the current time. The experimental make_array may be an indication that something is perhaps being considered.
    – Steven W. Klassen
    Nov 8 at 18:41




    My answer isn’t make_array, my answer is no there isn’t at the current time. The experimental make_array may be an indication that something is perhaps being considered.
    – Steven W. Klassen
    Nov 8 at 18:41












    That said, there are some techniques being listed here that could yet prove me wrong. (Perhaps the answer is not ‘no’.)
    – Steven W. Klassen
    Nov 8 at 18:43




    That said, there are some techniques being listed here that could yet prove me wrong. (Perhaps the answer is not ‘no’.)
    – Steven W. Klassen
    Nov 8 at 18:43




    1




    1




    This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. - From Review
    – Ken Y-N
    Nov 8 at 23:48




    This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. - From Review
    – Ken Y-N
    Nov 8 at 23:48




    1




    1




    The reviewers have a divided opinion of my post with half saying delete and half saying it is ok. Before going the delete route, I'm going to rephrase my answer and explain in more detail why I believe the correct answer is in fact (and unfortunately) "no".
    – Steven W. Klassen
    Nov 9 at 8:02




    The reviewers have a divided opinion of my post with half saying delete and half saying it is ok. Before going the delete route, I'm going to rephrase my answer and explain in more detail why I believe the correct answer is in fact (and unfortunately) "no".
    – Steven W. Klassen
    Nov 9 at 8:02











    1














    Here's one approach that allows you to specify the type. We use an extra argument to specify the type, so that we can still use the deduction guide to pick up the size. I don't consider it pretty though:



    #include <iostream>

    template <typename T>
    struct Tag ;

    template <typename T, size_t N>
    struct Array
    T data_[N];

    template <typename... U>
    Array(Tag<T>, U... u)
    : data_static_cast<T>(u)... // cast to shut up narrowing conversions - bad idea??

    ;

    template <typename T, typename... U>
    Array(Tag<T>, U...) -> Array<T, sizeof...(U)>;

    int main()

    Array aTag<double>, 1, 2.0f, 3.0;
    for (auto d : a.data_)
    std::cout << d << 'n';




    This is clearly not a full implementation of such a class, just to illustrate the technique.






    share|improve this answer


















    • 1




      Nice; I suggest to add, a SFINAE enable check in template signature (something as template <typename ... U, typename = std::enable_if_t<N == sizeof...(U)>> (or maybe is enough sizeof...(U) <= N) to avoid that someone can write something as Array<int, 2> aTag<int>, 1, 2, 3;
      – max66
      Nov 8 at 15:07















    1














    Here's one approach that allows you to specify the type. We use an extra argument to specify the type, so that we can still use the deduction guide to pick up the size. I don't consider it pretty though:



    #include <iostream>

    template <typename T>
    struct Tag ;

    template <typename T, size_t N>
    struct Array
    T data_[N];

    template <typename... U>
    Array(Tag<T>, U... u)
    : data_static_cast<T>(u)... // cast to shut up narrowing conversions - bad idea??

    ;

    template <typename T, typename... U>
    Array(Tag<T>, U...) -> Array<T, sizeof...(U)>;

    int main()

    Array aTag<double>, 1, 2.0f, 3.0;
    for (auto d : a.data_)
    std::cout << d << 'n';




    This is clearly not a full implementation of such a class, just to illustrate the technique.






    share|improve this answer


















    • 1




      Nice; I suggest to add, a SFINAE enable check in template signature (something as template <typename ... U, typename = std::enable_if_t<N == sizeof...(U)>> (or maybe is enough sizeof...(U) <= N) to avoid that someone can write something as Array<int, 2> aTag<int>, 1, 2, 3;
      – max66
      Nov 8 at 15:07













    1












    1








    1






    Here's one approach that allows you to specify the type. We use an extra argument to specify the type, so that we can still use the deduction guide to pick up the size. I don't consider it pretty though:



    #include <iostream>

    template <typename T>
    struct Tag ;

    template <typename T, size_t N>
    struct Array
    T data_[N];

    template <typename... U>
    Array(Tag<T>, U... u)
    : data_static_cast<T>(u)... // cast to shut up narrowing conversions - bad idea??

    ;

    template <typename T, typename... U>
    Array(Tag<T>, U...) -> Array<T, sizeof...(U)>;

    int main()

    Array aTag<double>, 1, 2.0f, 3.0;
    for (auto d : a.data_)
    std::cout << d << 'n';




    This is clearly not a full implementation of such a class, just to illustrate the technique.






    share|improve this answer














    Here's one approach that allows you to specify the type. We use an extra argument to specify the type, so that we can still use the deduction guide to pick up the size. I don't consider it pretty though:



    #include <iostream>

    template <typename T>
    struct Tag ;

    template <typename T, size_t N>
    struct Array
    T data_[N];

    template <typename... U>
    Array(Tag<T>, U... u)
    : data_static_cast<T>(u)... // cast to shut up narrowing conversions - bad idea??

    ;

    template <typename T, typename... U>
    Array(Tag<T>, U...) -> Array<T, sizeof...(U)>;

    int main()

    Array aTag<double>, 1, 2.0f, 3.0;
    for (auto d : a.data_)
    std::cout << d << 'n';




    This is clearly not a full implementation of such a class, just to illustrate the technique.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 8 at 15:48

























    answered Nov 8 at 15:03









    BoBTFish

    14.6k23457




    14.6k23457







    • 1




      Nice; I suggest to add, a SFINAE enable check in template signature (something as template <typename ... U, typename = std::enable_if_t<N == sizeof...(U)>> (or maybe is enough sizeof...(U) <= N) to avoid that someone can write something as Array<int, 2> aTag<int>, 1, 2, 3;
      – max66
      Nov 8 at 15:07












    • 1




      Nice; I suggest to add, a SFINAE enable check in template signature (something as template <typename ... U, typename = std::enable_if_t<N == sizeof...(U)>> (or maybe is enough sizeof...(U) <= N) to avoid that someone can write something as Array<int, 2> aTag<int>, 1, 2, 3;
      – max66
      Nov 8 at 15:07







    1




    1




    Nice; I suggest to add, a SFINAE enable check in template signature (something as template <typename ... U, typename = std::enable_if_t<N == sizeof...(U)>> (or maybe is enough sizeof...(U) <= N) to avoid that someone can write something as Array<int, 2> aTag<int>, 1, 2, 3;
    – max66
    Nov 8 at 15:07




    Nice; I suggest to add, a SFINAE enable check in template signature (something as template <typename ... U, typename = std::enable_if_t<N == sizeof...(U)>> (or maybe is enough sizeof...(U) <= N) to avoid that someone can write something as Array<int, 2> aTag<int>, 1, 2, 3;
    – max66
    Nov 8 at 15:07











    1















    Deduction guides in C++17 nearly work, but you have to omit the type parameter and all items must have exactly the same type




    Not necessarily.



    Yes, you can't explicit the type parameter, but you can decide it according the types of the items.



    I imagine two reasonable strategies: (1) the type of the Array is the type of the first item, following the std::array way, so writing the following deduction guide



    template <typename T, typename ... Us>
    Array(T, Us...) -> Array<T, 1u + sizeof...(Us)>;


    (but observe that a C++ program where a Us type is different from T, for a std::array, is ill formed) or (2) follows the metalfox's suggestion and select the item's common type



    template <typename ... Ts>
    Array(Ts...) -> Array<std::common_type_t<Ts...>, sizeof...(Ts)>;



    Is the braced-init-list to T[N] that happens in int foo = 1, 2, 3 ; purely compiler magic that can't be replicated in code?




    Are you thinking in a deduction guide as follows ?



    template <typename T, std::size_t N>
    Array(T const (&)[N]) -> Array<T, N>;


    Works but with a couple of drawbacks: (1) you have to add a couple of brackets using it



    // added ---V V--- added
    Array foo1 = 1, 2, 3 ; // Works


    and (2) remain the problem that all items must have the same type



    Array foo2 = 1.0, 2.0, 3.0f ; //Doesn't work: incompatible types


    or the compiler can't deduce the type T



    P.s.: what's wrong with a make_array() function ?



    P.s.2: I suggest to give a look at BoBTFish's answer to see a nice method to bypass the impossibility to explicit a template argument using deduction guides.






    share|improve this answer



























      1















      Deduction guides in C++17 nearly work, but you have to omit the type parameter and all items must have exactly the same type




      Not necessarily.



      Yes, you can't explicit the type parameter, but you can decide it according the types of the items.



      I imagine two reasonable strategies: (1) the type of the Array is the type of the first item, following the std::array way, so writing the following deduction guide



      template <typename T, typename ... Us>
      Array(T, Us...) -> Array<T, 1u + sizeof...(Us)>;


      (but observe that a C++ program where a Us type is different from T, for a std::array, is ill formed) or (2) follows the metalfox's suggestion and select the item's common type



      template <typename ... Ts>
      Array(Ts...) -> Array<std::common_type_t<Ts...>, sizeof...(Ts)>;



      Is the braced-init-list to T[N] that happens in int foo = 1, 2, 3 ; purely compiler magic that can't be replicated in code?




      Are you thinking in a deduction guide as follows ?



      template <typename T, std::size_t N>
      Array(T const (&)[N]) -> Array<T, N>;


      Works but with a couple of drawbacks: (1) you have to add a couple of brackets using it



      // added ---V V--- added
      Array foo1 = 1, 2, 3 ; // Works


      and (2) remain the problem that all items must have the same type



      Array foo2 = 1.0, 2.0, 3.0f ; //Doesn't work: incompatible types


      or the compiler can't deduce the type T



      P.s.: what's wrong with a make_array() function ?



      P.s.2: I suggest to give a look at BoBTFish's answer to see a nice method to bypass the impossibility to explicit a template argument using deduction guides.






      share|improve this answer

























        1












        1








        1







        Deduction guides in C++17 nearly work, but you have to omit the type parameter and all items must have exactly the same type




        Not necessarily.



        Yes, you can't explicit the type parameter, but you can decide it according the types of the items.



        I imagine two reasonable strategies: (1) the type of the Array is the type of the first item, following the std::array way, so writing the following deduction guide



        template <typename T, typename ... Us>
        Array(T, Us...) -> Array<T, 1u + sizeof...(Us)>;


        (but observe that a C++ program where a Us type is different from T, for a std::array, is ill formed) or (2) follows the metalfox's suggestion and select the item's common type



        template <typename ... Ts>
        Array(Ts...) -> Array<std::common_type_t<Ts...>, sizeof...(Ts)>;



        Is the braced-init-list to T[N] that happens in int foo = 1, 2, 3 ; purely compiler magic that can't be replicated in code?




        Are you thinking in a deduction guide as follows ?



        template <typename T, std::size_t N>
        Array(T const (&)[N]) -> Array<T, N>;


        Works but with a couple of drawbacks: (1) you have to add a couple of brackets using it



        // added ---V V--- added
        Array foo1 = 1, 2, 3 ; // Works


        and (2) remain the problem that all items must have the same type



        Array foo2 = 1.0, 2.0, 3.0f ; //Doesn't work: incompatible types


        or the compiler can't deduce the type T



        P.s.: what's wrong with a make_array() function ?



        P.s.2: I suggest to give a look at BoBTFish's answer to see a nice method to bypass the impossibility to explicit a template argument using deduction guides.






        share|improve this answer















        Deduction guides in C++17 nearly work, but you have to omit the type parameter and all items must have exactly the same type




        Not necessarily.



        Yes, you can't explicit the type parameter, but you can decide it according the types of the items.



        I imagine two reasonable strategies: (1) the type of the Array is the type of the first item, following the std::array way, so writing the following deduction guide



        template <typename T, typename ... Us>
        Array(T, Us...) -> Array<T, 1u + sizeof...(Us)>;


        (but observe that a C++ program where a Us type is different from T, for a std::array, is ill formed) or (2) follows the metalfox's suggestion and select the item's common type



        template <typename ... Ts>
        Array(Ts...) -> Array<std::common_type_t<Ts...>, sizeof...(Ts)>;



        Is the braced-init-list to T[N] that happens in int foo = 1, 2, 3 ; purely compiler magic that can't be replicated in code?




        Are you thinking in a deduction guide as follows ?



        template <typename T, std::size_t N>
        Array(T const (&)[N]) -> Array<T, N>;


        Works but with a couple of drawbacks: (1) you have to add a couple of brackets using it



        // added ---V V--- added
        Array foo1 = 1, 2, 3 ; // Works


        and (2) remain the problem that all items must have the same type



        Array foo2 = 1.0, 2.0, 3.0f ; //Doesn't work: incompatible types


        or the compiler can't deduce the type T



        P.s.: what's wrong with a make_array() function ?



        P.s.2: I suggest to give a look at BoBTFish's answer to see a nice method to bypass the impossibility to explicit a template argument using deduction guides.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 8 at 17:00

























        answered Nov 8 at 13:59









        max66

        34.2k63762




        34.2k63762





















            0














            You had asked this:




            Q: Is there anyway to create an Array class that can be initialized with a braced-init-list without having to manually specify the array length, and without a 'make_array' function.




            I have worked on an implementation of a class that behaves in the manner you are describing only it has a little bit more complexity to it but still fairly simple, readable, reusable, portable and generic.



            I was not able to have a T items array as a direct member in the class. I had to use a T* items instead and create an overloaded operator in the derived class to mimic the behavior of an array. This doesn't mean that there isn't any work around to this as others have shown. I just find that this is one possible solution without having to specify the size of the array.



            I use a base class to store the elements from the constructor either by means of an std::initializer_list or of a variadic constructor. The class templates themselves are not a variadic template only their constructor's are. The base class stores the values from the initializer_list or parameter pack into an std::vector. The inherited class stores the contents from the vector into T* by calling the data() function of the vector class.



            template<typename T>
            class ParamPack
            protected:
            std::vector<T> values_;
            size_t size_;
            public:
            template<typename... U>
            ParamPack( U... u ) :
            values_ static_cast<T>(u)... ,
            size_( sizeof...(U) )

            template<typename ... U>
            ParamPack( std::initializer_list<std::is_same<T, U...>( U...)> il ) :
            values_( il ), size_( il.size() )

            std::vector<T>& operator()() return values_;

            size_t size() const return size_;
            ;

            template<typename T>
            class Array : public ParamPack<T>
            private:
            T* items_;
            public:
            template<typename... U>
            Array( U... u ) : ParamPack<T>::ParamPack( u... )
            items_ = this->values_.data();


            template<typename... U>
            Array( std::initializer_list<U...> il ) : ParamPack<T>::ParamPack( il )
            items_ = this->values_.data();


            T& operator( size_t idx )
            return items_[idx];


            T operator( size_t idx ) const
            return items_[idx];


            T* data() const return items_;
            ;

            int main()
            try
            // Parameter Pack Examples:
            // Variadic Constructor ...
            std::cout << "ParamPack<T> Examples:n";
            std::cout << "Using ParamPack<T>'s Variadic Constructorn";
            ParamPack<int> pp1( 1, 2, 3, 4 );
            std::cout << "Size: " << pp1.size() << " catch( const std::runtime_error& e )
            std::cerr << e.what() << 'n';
            return EXIT_FAILURE;


            return EXIT_SUCCESS;



            -Output-



            ParamPack<T> Examples:
            Using ParamPack<T>'s Variadic Constructor
            Size: 4 | Elements: 1 2 3 4
            Using ParamPack<T>'s Variadic Constructor with an Initializer List
            Size: 4 | Elements: 5 6 7 8
            Using ParamPack<T>'s initializer_list Constructor
            Size: 4 | Elements: 9 10 11 12

            Array<T> Examples:
            Using Array<T>'s initializer_list Constructor
            9 10 12 12

            Using Array<T>'s Variadic Constructor
            9 8 7 6
            Hello World

            Using Array<T>'s Constructor with Initializer List
            105 210 420

            Using Array<T>'s Initializer List with =
            1 2 3 4
            a b c d
            1.2 3.4 5.6 7.8

            Using Array<T>'s Initializer List directly
            3 6 9 12

            Using Array<T>'s Variadic Constructor with user data type
            (1,2) (3,4) (5,6)
            Using Array<T>'s Variadic Constructor With Initializer List of user data type
            (5,6) (3,4) (1,2)
            Using Array<T>'s = Initializer List with user data type
            (3,4) (1,2) (5,6)
            Using Array<T>'s Initializer List directly with user data type
            (3,4) (5,6) (1,2)
            Using Array<T>'s initializer_list Constructor with user data type

            Using Array<T>'s base class's operator()() to retrieve vector
            (3,4) (5,6) (1,2)
            Using Array<T>'s data() to get the contents of its internal pointer
            (3,4) (5,6) (1,2)


            Now this is a little more robust as it has operators that are available from both the parent and child class, from the parent class you can get the stored vector directly from its operator()(). From the child class you can index into the child's stored pointer from operator() and there is a function to return it's size. The template itself does not contain a size_t N template argument since the size is stored internally in the base class and is determined by the size of its vector. With this I'm treating T* p as if it was T p[size]. This class is still not without some limitations.



            -Valid Construction-



            Array<int> a( 1, 2, 3, 4 ); // Variadic Constructor Okay
            Array<int> a( 1,2,3,4 ); // Initializer List Constructor Okay
            Array<int> a = 1, 2, 3, 4 ; // Initializer List Okay
            Array<int> a 1,2,3,4 ; // Initializer List Okay


            -Limitations-



            However you have to explicitly instantiate the template as these will not work as they all generate a compiler error.



            Array a( 1,2,3,4 );
            Array a( 1,2,3,4 );
            Array a = 1, 2, 3, 4 ;
            Array a 1,2,3,4 ;


            -Note- There maybe more that can be done to make this more efficient, maybe even thread safe or exception safe, but this is just a generalization of the class design.




            Please let me know what you think about this:






            share|improve this answer






















            • I appreciate your thoroughness. However, this answer boils down to 'allocate and copy elements into a vector' and it's needlessly complex even for that case. The defining features of an array are no dynamic allocation and a compile time known size.
              – Adam
              Nov 10 at 19:28










            • @Adam I know, but the problem with trying to not specific the array's size by inferring it from the amount of the parameters passed into the initializer list's constructor will not work because the size of the array has to be known at compile time. Even though you are calling the constructor on the class, the compiler has to set aside memory for the class and all of its members before it can call its ctor and thus it can not create the array without knowing how many elements of type T to reserve for the class's construction.
              – Francis Cugler
              Nov 11 at 7:10










            • @Adam also your question is a very good question. I posted this answer because I enjoyed the attempt at trying to mimic a C arrays behavior. There are no direct issues with the code above, maybe some room for efficiency, but in the output section I'm kind of wording some of it wrong. Non of the examples are using the 2nd constructor of the two classes. They are all using the 1st constructor which is the variadic version. I'm working on it now to update the main and it's output to make it more clear.
              – Francis Cugler
              Nov 11 at 7:12















            0














            You had asked this:




            Q: Is there anyway to create an Array class that can be initialized with a braced-init-list without having to manually specify the array length, and without a 'make_array' function.




            I have worked on an implementation of a class that behaves in the manner you are describing only it has a little bit more complexity to it but still fairly simple, readable, reusable, portable and generic.



            I was not able to have a T items array as a direct member in the class. I had to use a T* items instead and create an overloaded operator in the derived class to mimic the behavior of an array. This doesn't mean that there isn't any work around to this as others have shown. I just find that this is one possible solution without having to specify the size of the array.



            I use a base class to store the elements from the constructor either by means of an std::initializer_list or of a variadic constructor. The class templates themselves are not a variadic template only their constructor's are. The base class stores the values from the initializer_list or parameter pack into an std::vector. The inherited class stores the contents from the vector into T* by calling the data() function of the vector class.



            template<typename T>
            class ParamPack
            protected:
            std::vector<T> values_;
            size_t size_;
            public:
            template<typename... U>
            ParamPack( U... u ) :
            values_ static_cast<T>(u)... ,
            size_( sizeof...(U) )

            template<typename ... U>
            ParamPack( std::initializer_list<std::is_same<T, U...>( U...)> il ) :
            values_( il ), size_( il.size() )

            std::vector<T>& operator()() return values_;

            size_t size() const return size_;
            ;

            template<typename T>
            class Array : public ParamPack<T>
            private:
            T* items_;
            public:
            template<typename... U>
            Array( U... u ) : ParamPack<T>::ParamPack( u... )
            items_ = this->values_.data();


            template<typename... U>
            Array( std::initializer_list<U...> il ) : ParamPack<T>::ParamPack( il )
            items_ = this->values_.data();


            T& operator( size_t idx )
            return items_[idx];


            T operator( size_t idx ) const
            return items_[idx];


            T* data() const return items_;
            ;

            int main()
            try
            // Parameter Pack Examples:
            // Variadic Constructor ...
            std::cout << "ParamPack<T> Examples:n";
            std::cout << "Using ParamPack<T>'s Variadic Constructorn";
            ParamPack<int> pp1( 1, 2, 3, 4 );
            std::cout << "Size: " << pp1.size() << " catch( const std::runtime_error& e )
            std::cerr << e.what() << 'n';
            return EXIT_FAILURE;


            return EXIT_SUCCESS;



            -Output-



            ParamPack<T> Examples:
            Using ParamPack<T>'s Variadic Constructor
            Size: 4 | Elements: 1 2 3 4
            Using ParamPack<T>'s Variadic Constructor with an Initializer List
            Size: 4 | Elements: 5 6 7 8
            Using ParamPack<T>'s initializer_list Constructor
            Size: 4 | Elements: 9 10 11 12

            Array<T> Examples:
            Using Array<T>'s initializer_list Constructor
            9 10 12 12

            Using Array<T>'s Variadic Constructor
            9 8 7 6
            Hello World

            Using Array<T>'s Constructor with Initializer List
            105 210 420

            Using Array<T>'s Initializer List with =
            1 2 3 4
            a b c d
            1.2 3.4 5.6 7.8

            Using Array<T>'s Initializer List directly
            3 6 9 12

            Using Array<T>'s Variadic Constructor with user data type
            (1,2) (3,4) (5,6)
            Using Array<T>'s Variadic Constructor With Initializer List of user data type
            (5,6) (3,4) (1,2)
            Using Array<T>'s = Initializer List with user data type
            (3,4) (1,2) (5,6)
            Using Array<T>'s Initializer List directly with user data type
            (3,4) (5,6) (1,2)
            Using Array<T>'s initializer_list Constructor with user data type

            Using Array<T>'s base class's operator()() to retrieve vector
            (3,4) (5,6) (1,2)
            Using Array<T>'s data() to get the contents of its internal pointer
            (3,4) (5,6) (1,2)


            Now this is a little more robust as it has operators that are available from both the parent and child class, from the parent class you can get the stored vector directly from its operator()(). From the child class you can index into the child's stored pointer from operator() and there is a function to return it's size. The template itself does not contain a size_t N template argument since the size is stored internally in the base class and is determined by the size of its vector. With this I'm treating T* p as if it was T p[size]. This class is still not without some limitations.



            -Valid Construction-



            Array<int> a( 1, 2, 3, 4 ); // Variadic Constructor Okay
            Array<int> a( 1,2,3,4 ); // Initializer List Constructor Okay
            Array<int> a = 1, 2, 3, 4 ; // Initializer List Okay
            Array<int> a 1,2,3,4 ; // Initializer List Okay


            -Limitations-



            However you have to explicitly instantiate the template as these will not work as they all generate a compiler error.



            Array a( 1,2,3,4 );
            Array a( 1,2,3,4 );
            Array a = 1, 2, 3, 4 ;
            Array a 1,2,3,4 ;


            -Note- There maybe more that can be done to make this more efficient, maybe even thread safe or exception safe, but this is just a generalization of the class design.




            Please let me know what you think about this:






            share|improve this answer






















            • I appreciate your thoroughness. However, this answer boils down to 'allocate and copy elements into a vector' and it's needlessly complex even for that case. The defining features of an array are no dynamic allocation and a compile time known size.
              – Adam
              Nov 10 at 19:28










            • @Adam I know, but the problem with trying to not specific the array's size by inferring it from the amount of the parameters passed into the initializer list's constructor will not work because the size of the array has to be known at compile time. Even though you are calling the constructor on the class, the compiler has to set aside memory for the class and all of its members before it can call its ctor and thus it can not create the array without knowing how many elements of type T to reserve for the class's construction.
              – Francis Cugler
              Nov 11 at 7:10










            • @Adam also your question is a very good question. I posted this answer because I enjoyed the attempt at trying to mimic a C arrays behavior. There are no direct issues with the code above, maybe some room for efficiency, but in the output section I'm kind of wording some of it wrong. Non of the examples are using the 2nd constructor of the two classes. They are all using the 1st constructor which is the variadic version. I'm working on it now to update the main and it's output to make it more clear.
              – Francis Cugler
              Nov 11 at 7:12













            0












            0








            0






            You had asked this:




            Q: Is there anyway to create an Array class that can be initialized with a braced-init-list without having to manually specify the array length, and without a 'make_array' function.




            I have worked on an implementation of a class that behaves in the manner you are describing only it has a little bit more complexity to it but still fairly simple, readable, reusable, portable and generic.



            I was not able to have a T items array as a direct member in the class. I had to use a T* items instead and create an overloaded operator in the derived class to mimic the behavior of an array. This doesn't mean that there isn't any work around to this as others have shown. I just find that this is one possible solution without having to specify the size of the array.



            I use a base class to store the elements from the constructor either by means of an std::initializer_list or of a variadic constructor. The class templates themselves are not a variadic template only their constructor's are. The base class stores the values from the initializer_list or parameter pack into an std::vector. The inherited class stores the contents from the vector into T* by calling the data() function of the vector class.



            template<typename T>
            class ParamPack
            protected:
            std::vector<T> values_;
            size_t size_;
            public:
            template<typename... U>
            ParamPack( U... u ) :
            values_ static_cast<T>(u)... ,
            size_( sizeof...(U) )

            template<typename ... U>
            ParamPack( std::initializer_list<std::is_same<T, U...>( U...)> il ) :
            values_( il ), size_( il.size() )

            std::vector<T>& operator()() return values_;

            size_t size() const return size_;
            ;

            template<typename T>
            class Array : public ParamPack<T>
            private:
            T* items_;
            public:
            template<typename... U>
            Array( U... u ) : ParamPack<T>::ParamPack( u... )
            items_ = this->values_.data();


            template<typename... U>
            Array( std::initializer_list<U...> il ) : ParamPack<T>::ParamPack( il )
            items_ = this->values_.data();


            T& operator( size_t idx )
            return items_[idx];


            T operator( size_t idx ) const
            return items_[idx];


            T* data() const return items_;
            ;

            int main()
            try
            // Parameter Pack Examples:
            // Variadic Constructor ...
            std::cout << "ParamPack<T> Examples:n";
            std::cout << "Using ParamPack<T>'s Variadic Constructorn";
            ParamPack<int> pp1( 1, 2, 3, 4 );
            std::cout << "Size: " << pp1.size() << " catch( const std::runtime_error& e )
            std::cerr << e.what() << 'n';
            return EXIT_FAILURE;


            return EXIT_SUCCESS;



            -Output-



            ParamPack<T> Examples:
            Using ParamPack<T>'s Variadic Constructor
            Size: 4 | Elements: 1 2 3 4
            Using ParamPack<T>'s Variadic Constructor with an Initializer List
            Size: 4 | Elements: 5 6 7 8
            Using ParamPack<T>'s initializer_list Constructor
            Size: 4 | Elements: 9 10 11 12

            Array<T> Examples:
            Using Array<T>'s initializer_list Constructor
            9 10 12 12

            Using Array<T>'s Variadic Constructor
            9 8 7 6
            Hello World

            Using Array<T>'s Constructor with Initializer List
            105 210 420

            Using Array<T>'s Initializer List with =
            1 2 3 4
            a b c d
            1.2 3.4 5.6 7.8

            Using Array<T>'s Initializer List directly
            3 6 9 12

            Using Array<T>'s Variadic Constructor with user data type
            (1,2) (3,4) (5,6)
            Using Array<T>'s Variadic Constructor With Initializer List of user data type
            (5,6) (3,4) (1,2)
            Using Array<T>'s = Initializer List with user data type
            (3,4) (1,2) (5,6)
            Using Array<T>'s Initializer List directly with user data type
            (3,4) (5,6) (1,2)
            Using Array<T>'s initializer_list Constructor with user data type

            Using Array<T>'s base class's operator()() to retrieve vector
            (3,4) (5,6) (1,2)
            Using Array<T>'s data() to get the contents of its internal pointer
            (3,4) (5,6) (1,2)


            Now this is a little more robust as it has operators that are available from both the parent and child class, from the parent class you can get the stored vector directly from its operator()(). From the child class you can index into the child's stored pointer from operator() and there is a function to return it's size. The template itself does not contain a size_t N template argument since the size is stored internally in the base class and is determined by the size of its vector. With this I'm treating T* p as if it was T p[size]. This class is still not without some limitations.



            -Valid Construction-



            Array<int> a( 1, 2, 3, 4 ); // Variadic Constructor Okay
            Array<int> a( 1,2,3,4 ); // Initializer List Constructor Okay
            Array<int> a = 1, 2, 3, 4 ; // Initializer List Okay
            Array<int> a 1,2,3,4 ; // Initializer List Okay


            -Limitations-



            However you have to explicitly instantiate the template as these will not work as they all generate a compiler error.



            Array a( 1,2,3,4 );
            Array a( 1,2,3,4 );
            Array a = 1, 2, 3, 4 ;
            Array a 1,2,3,4 ;


            -Note- There maybe more that can be done to make this more efficient, maybe even thread safe or exception safe, but this is just a generalization of the class design.




            Please let me know what you think about this:






            share|improve this answer














            You had asked this:




            Q: Is there anyway to create an Array class that can be initialized with a braced-init-list without having to manually specify the array length, and without a 'make_array' function.




            I have worked on an implementation of a class that behaves in the manner you are describing only it has a little bit more complexity to it but still fairly simple, readable, reusable, portable and generic.



            I was not able to have a T items array as a direct member in the class. I had to use a T* items instead and create an overloaded operator in the derived class to mimic the behavior of an array. This doesn't mean that there isn't any work around to this as others have shown. I just find that this is one possible solution without having to specify the size of the array.



            I use a base class to store the elements from the constructor either by means of an std::initializer_list or of a variadic constructor. The class templates themselves are not a variadic template only their constructor's are. The base class stores the values from the initializer_list or parameter pack into an std::vector. The inherited class stores the contents from the vector into T* by calling the data() function of the vector class.



            template<typename T>
            class ParamPack
            protected:
            std::vector<T> values_;
            size_t size_;
            public:
            template<typename... U>
            ParamPack( U... u ) :
            values_ static_cast<T>(u)... ,
            size_( sizeof...(U) )

            template<typename ... U>
            ParamPack( std::initializer_list<std::is_same<T, U...>( U...)> il ) :
            values_( il ), size_( il.size() )

            std::vector<T>& operator()() return values_;

            size_t size() const return size_;
            ;

            template<typename T>
            class Array : public ParamPack<T>
            private:
            T* items_;
            public:
            template<typename... U>
            Array( U... u ) : ParamPack<T>::ParamPack( u... )
            items_ = this->values_.data();


            template<typename... U>
            Array( std::initializer_list<U...> il ) : ParamPack<T>::ParamPack( il )
            items_ = this->values_.data();


            T& operator( size_t idx )
            return items_[idx];


            T operator( size_t idx ) const
            return items_[idx];


            T* data() const return items_;
            ;

            int main()
            try
            // Parameter Pack Examples:
            // Variadic Constructor ...
            std::cout << "ParamPack<T> Examples:n";
            std::cout << "Using ParamPack<T>'s Variadic Constructorn";
            ParamPack<int> pp1( 1, 2, 3, 4 );
            std::cout << "Size: " << pp1.size() << " catch( const std::runtime_error& e )
            std::cerr << e.what() << 'n';
            return EXIT_FAILURE;


            return EXIT_SUCCESS;



            -Output-



            ParamPack<T> Examples:
            Using ParamPack<T>'s Variadic Constructor
            Size: 4 | Elements: 1 2 3 4
            Using ParamPack<T>'s Variadic Constructor with an Initializer List
            Size: 4 | Elements: 5 6 7 8
            Using ParamPack<T>'s initializer_list Constructor
            Size: 4 | Elements: 9 10 11 12

            Array<T> Examples:
            Using Array<T>'s initializer_list Constructor
            9 10 12 12

            Using Array<T>'s Variadic Constructor
            9 8 7 6
            Hello World

            Using Array<T>'s Constructor with Initializer List
            105 210 420

            Using Array<T>'s Initializer List with =
            1 2 3 4
            a b c d
            1.2 3.4 5.6 7.8

            Using Array<T>'s Initializer List directly
            3 6 9 12

            Using Array<T>'s Variadic Constructor with user data type
            (1,2) (3,4) (5,6)
            Using Array<T>'s Variadic Constructor With Initializer List of user data type
            (5,6) (3,4) (1,2)
            Using Array<T>'s = Initializer List with user data type
            (3,4) (1,2) (5,6)
            Using Array<T>'s Initializer List directly with user data type
            (3,4) (5,6) (1,2)
            Using Array<T>'s initializer_list Constructor with user data type

            Using Array<T>'s base class's operator()() to retrieve vector
            (3,4) (5,6) (1,2)
            Using Array<T>'s data() to get the contents of its internal pointer
            (3,4) (5,6) (1,2)


            Now this is a little more robust as it has operators that are available from both the parent and child class, from the parent class you can get the stored vector directly from its operator()(). From the child class you can index into the child's stored pointer from operator() and there is a function to return it's size. The template itself does not contain a size_t N template argument since the size is stored internally in the base class and is determined by the size of its vector. With this I'm treating T* p as if it was T p[size]. This class is still not without some limitations.



            -Valid Construction-



            Array<int> a( 1, 2, 3, 4 ); // Variadic Constructor Okay
            Array<int> a( 1,2,3,4 ); // Initializer List Constructor Okay
            Array<int> a = 1, 2, 3, 4 ; // Initializer List Okay
            Array<int> a 1,2,3,4 ; // Initializer List Okay


            -Limitations-



            However you have to explicitly instantiate the template as these will not work as they all generate a compiler error.



            Array a( 1,2,3,4 );
            Array a( 1,2,3,4 );
            Array a = 1, 2, 3, 4 ;
            Array a 1,2,3,4 ;


            -Note- There maybe more that can be done to make this more efficient, maybe even thread safe or exception safe, but this is just a generalization of the class design.




            Please let me know what you think about this:







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 11 at 8:20

























            answered Nov 10 at 7:16









            Francis Cugler

            4,38211227




            4,38211227











            • I appreciate your thoroughness. However, this answer boils down to 'allocate and copy elements into a vector' and it's needlessly complex even for that case. The defining features of an array are no dynamic allocation and a compile time known size.
              – Adam
              Nov 10 at 19:28










            • @Adam I know, but the problem with trying to not specific the array's size by inferring it from the amount of the parameters passed into the initializer list's constructor will not work because the size of the array has to be known at compile time. Even though you are calling the constructor on the class, the compiler has to set aside memory for the class and all of its members before it can call its ctor and thus it can not create the array without knowing how many elements of type T to reserve for the class's construction.
              – Francis Cugler
              Nov 11 at 7:10










            • @Adam also your question is a very good question. I posted this answer because I enjoyed the attempt at trying to mimic a C arrays behavior. There are no direct issues with the code above, maybe some room for efficiency, but in the output section I'm kind of wording some of it wrong. Non of the examples are using the 2nd constructor of the two classes. They are all using the 1st constructor which is the variadic version. I'm working on it now to update the main and it's output to make it more clear.
              – Francis Cugler
              Nov 11 at 7:12
















            • I appreciate your thoroughness. However, this answer boils down to 'allocate and copy elements into a vector' and it's needlessly complex even for that case. The defining features of an array are no dynamic allocation and a compile time known size.
              – Adam
              Nov 10 at 19:28










            • @Adam I know, but the problem with trying to not specific the array's size by inferring it from the amount of the parameters passed into the initializer list's constructor will not work because the size of the array has to be known at compile time. Even though you are calling the constructor on the class, the compiler has to set aside memory for the class and all of its members before it can call its ctor and thus it can not create the array without knowing how many elements of type T to reserve for the class's construction.
              – Francis Cugler
              Nov 11 at 7:10










            • @Adam also your question is a very good question. I posted this answer because I enjoyed the attempt at trying to mimic a C arrays behavior. There are no direct issues with the code above, maybe some room for efficiency, but in the output section I'm kind of wording some of it wrong. Non of the examples are using the 2nd constructor of the two classes. They are all using the 1st constructor which is the variadic version. I'm working on it now to update the main and it's output to make it more clear.
              – Francis Cugler
              Nov 11 at 7:12















            I appreciate your thoroughness. However, this answer boils down to 'allocate and copy elements into a vector' and it's needlessly complex even for that case. The defining features of an array are no dynamic allocation and a compile time known size.
            – Adam
            Nov 10 at 19:28




            I appreciate your thoroughness. However, this answer boils down to 'allocate and copy elements into a vector' and it's needlessly complex even for that case. The defining features of an array are no dynamic allocation and a compile time known size.
            – Adam
            Nov 10 at 19:28












            @Adam I know, but the problem with trying to not specific the array's size by inferring it from the amount of the parameters passed into the initializer list's constructor will not work because the size of the array has to be known at compile time. Even though you are calling the constructor on the class, the compiler has to set aside memory for the class and all of its members before it can call its ctor and thus it can not create the array without knowing how many elements of type T to reserve for the class's construction.
            – Francis Cugler
            Nov 11 at 7:10




            @Adam I know, but the problem with trying to not specific the array's size by inferring it from the amount of the parameters passed into the initializer list's constructor will not work because the size of the array has to be known at compile time. Even though you are calling the constructor on the class, the compiler has to set aside memory for the class and all of its members before it can call its ctor and thus it can not create the array without knowing how many elements of type T to reserve for the class's construction.
            – Francis Cugler
            Nov 11 at 7:10












            @Adam also your question is a very good question. I posted this answer because I enjoyed the attempt at trying to mimic a C arrays behavior. There are no direct issues with the code above, maybe some room for efficiency, but in the output section I'm kind of wording some of it wrong. Non of the examples are using the 2nd constructor of the two classes. They are all using the 1st constructor which is the variadic version. I'm working on it now to update the main and it's output to make it more clear.
            – Francis Cugler
            Nov 11 at 7:12




            @Adam also your question is a very good question. I posted this answer because I enjoyed the attempt at trying to mimic a C arrays behavior. There are no direct issues with the code above, maybe some room for efficiency, but in the output section I'm kind of wording some of it wrong. Non of the examples are using the 2nd constructor of the two classes. They are all using the 1st constructor which is the variadic version. I'm working on it now to update the main and it's output to make it more clear.
            – Francis Cugler
            Nov 11 at 7:12

















            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53203629%2farray-class-that-will-accept-an-braced-init-list-and-deduce-length%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Use pre created SQLite database for Android project in kotlin

            Darth Vader #20

            Ondo