Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error when instantiating std::array using std::array::size

Example code test.cpp

#include <array>
#include <string>

int main ()
{
  // OK
  const std::array<int, 2> array_int = {42, 1337};

  std::array<float, array_int.size()> array_float_ok;

  // Error
  const std::array<std::string, 2> array_string = {"foo", "bar"};

  std::array<float, array_string.size()> array_float_error;

  return 0;
}

Compiling with g++ 4.8.4 (Ubuntu 14.04)

g++ -Wall -std=c++0x test.cpp -o test

Gives the following error message

test.cpp: In function ‘int main()’:
test.cpp:14:39: error: call to non-constexpr function ‘constexpr std::array<_Tp, _Nm>::size_type std::array<_Tp, _Nm>::size() const [with _Tp = std::basic_string<char>; long unsigned int _Nm = 2ul; std::array<_Tp, _Nm>::size_type = long unsigned int]’
   std::array<float, array_string.size()> array_float_error;
                                       ^
In file included from test.cpp:1:0:
/usr/include/c++/4.8/array:162:7: note: ‘constexpr std::array<_Tp, _Nm>::size_type std::array<_Tp, _Nm>::size() const [with _Tp = std::basic_string<char>; long unsigned int _Nm = 2ul; std::array<_Tp, _Nm>::size_type = long unsigned int]’ is not usable as a constexpr function because:
       size() const noexcept { return _Nm; }
       ^
/usr/include/c++/4.8/array:162:7: error: enclosing class of constexpr non-static member function ‘constexpr std::array<_Tp, _Nm>::size_type std::array<_Tp, _Nm>::size() const [with _Tp = std::basic_string<char>; long unsigned int _Nm = 2ul; std::array<_Tp, _Nm>::size_type = long unsigned int]’ is not a literal type
/usr/include/c++/4.8/array:81:12: note: ‘std::array<std::basic_string<char>, 2ul>’ is not literal because:
     struct array
            ^
/usr/include/c++/4.8/array:81:12: note:   ‘std::array<std::basic_string<char>, 2ul>’ has a non-trivial destructor
test.cpp:14:39: error: call to non-constexpr function ‘constexpr std::array<_Tp, _Nm>::size_type std::array<_Tp, _Nm>::size() const [with _Tp = std::basic_string<char>; long unsigned int _Nm = 2ul; std::array<_Tp, _Nm>::size_type = long unsigned int]’
   std::array<float, array_string.size()> array_float_error;
                                       ^
test.cpp:14:40: note: in template argument for type ‘long unsigned int’
   std::array<float, array_string.size()> array_float_error;
                                        ^
test.cpp:14:59: error: invalid type in declaration before ‘;’ token
   std::array<float, array_string.size()> array_float_error;
                                                           ^
test.cpp:9:39: warning: unused variable ‘array_float_ok’ [-Wunused-variable]
   std::array<float, array_int.size()> array_float_ok;
                                       ^
test.cpp:14:42: warning: unused variable ‘array_float_error’ [-Wunused-variable]
   std::array<float, array_string.size()> array_float_error;
                                          ^

Can someone explain this error? Why does the first example work while the second one does not compile?

like image 515
simon Avatar asked Feb 12 '16 10:02

simon


People also ask

Is std :: array fixed size?

std::array is a container that encapsulates fixed size arrays. This container is an aggregate type with the same semantics as a struct holding a C-style array T[N] as its only non-static data member. Unlike a C-style array, it doesn't decay to T* automatically.

Does std :: array initialize?

std::array contains a built-in array, which can be initialized via an initializer list, which is what the inner set is. The outer set is for aggregate initialization.

How do you initialize an array of STD in C++?

Like arrays, we initialize an std::array by simply assigning it values at the time of declaration. For example, we will initialize an integer type std::array named 'n' of length 5 as shown below; std::array<int, 5> n = {1, 2, 3, 4, 5}; There is another way of initializing an std::array which is shown below.

Should you use std :: array?

You should not notice any difference in runtime performance while you still get to enjoy the extra features. Using std::array instead of int[] style arrays is a good idea if you have C++11 or boost at hand.


1 Answers

The type std::string is not a literal type meaning that it cannot be manipulated as part of a constexpr function at compile time. At compile time, the compiler attempts to evaluate the array_string's size() function. The functions first type parameter as you can see in the first error is set to std::basic_string < char > (aka std::string); therefore, since std::string is not a literal type, the function cannot be evaluated as a constexpr function at compile time and you have an error.

I would refer you to the following to learn more about constexpr.

http://en.cppreference.com/w/cpp/language/constexpr

I would refer you to the following to learn about literal types.

http://en.cppreference.com/w/cpp/concept/LiteralType

Finally, try the following simple code and you will see that int and float are literal types and std::string is not. You can try it out with other types to see what are or aren't literal types.

#include <iostream>
int main(int argc, char** argv) 
{ 
    std::cout << std::is_literal_type<int>::value << std::endl;
    std::cout << std::is_literal_type<float>::value << std::endl;
    std::cout << std::is_literal_type<std::string>::value << std::endl;
    return 0;
}                                  

Hope that helps.

John

like image 92
jjaguayo Avatar answered Oct 15 '22 02:10

jjaguayo