Is there a way to enforce full initialization of std::array

后端 未结 3 1596
耶瑟儿~
耶瑟儿~ 2021-01-02 05:18

I am using std::array (N is a fixed template-variable).

#include
template
struct A{
   size_t fun         


        
相关标签:
3条回答
  • 2021-01-02 05:48

    You can create a wrapper for your objects

    template <class T>
    struct WrapT
    {
        WrapT() = delete;
    
        WrapT(T e)   : value(e){}
    
       public: T value; 
       // or add some operator()
    };
    

    and

    size_t function(std::array<WrapT<size_t>, N> arr){ return arr[N-1].value;}
    

    so a function call like (with full brace-init)

    function({ {{1}, {2}, {3}, {4}} }); 
    

    will not compile because of use of deleted function. Live example. The syntax is a little clumsy, and even then I'm not sure all the possible value-initialization cases are covered.

    @dpy points out you may omit the innermost ones, so you get to your original code: function( {{ 1, 2, 3, 4, 5 }} ).

    0 讨论(0)
  • 2021-01-02 05:53

    Simple answer: You cannot.

    When initializing std::array with a list, it is doing an aggregate initialization, and it is explained here when the list size is less than the number of member:

    • If the number of initializer clauses is less than the number of members or initializer list is completely empty, the remaining members are initialized by their brace-or-equal initializers, if provided in the class definition, and otherwise (since C++14) by empty lists, which performs value-initialization. If a member of a reference type is one of these remaining members, the program is ill-formed (references cannot be value-initialized)

    It is simply a legal and acceptable behavior to provide less than the size list, so compiler will not complain anything. Your code:

    A<5> a;
    a.function({{1,2,3}}));
    

    is equivalent to:

    A<5> a;
    a.function({{1,2,3,0,0}}));
    

    to compiler. Your best bet is runtime error (which may not be as you wished).

    0 讨论(0)
  • 2021-01-02 05:59

    You can enforce this by using parameter pack, but with a bit different syntax:

    #include <array>
    
    template<size_t N>
    struct A{
       template<typename... T>
       size_t function(T&&... nums)
       {
         static_assert(sizeof...(nums) == N, "Wrong number of arguments");
         std::array<size_t, N> arr = { std::forward<size_t>(nums)... };
         return arr[N-1];
       }
    };
    
    int main(){
       A<5> a;
       a.function(1,2,3,4,5); // OK
       a.function(1,2,4,5);   // Compile-time error
    }
    

    But, I think there is no good way to enforce that in compile time. I would just use assert(il.size() == N) in production code to check size of initializer list.

    0 讨论(0)
提交回复
热议问题