6

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?

simon
  • 1,125
  • 1
  • 10
  • 20
  • Definite dupe - have seen this question a few times recently – Lightness Races in Orbit Feb 12 '16 at 11:15
  • Possible duplicate of [constexpr and bizzare error](http://stackoverflow.com/questions/9607279/constexpr-and-bizzare-error) – mindriot Feb 12 '16 at 11:17
  • 3
    Possible duplicate of [Getting the number of elements in std::array at compile time](http://stackoverflow.com/questions/16866033/getting-the-number-of-elements-in-stdarray-at-compile-time) – sergej Feb 12 '16 at 11:25
  • I don't completely understand the answer given in the linked question. It mentions that "a1 isn't a constexpr value" (because std::string cannot be constexpr) which in my case corresponds to array_string. Does that mean array_int is a constexpr value implicitly (as I didn't specify it as constexpr)? – simon Feb 12 '16 at 12:24
  • @simon This looks like compiler error in gcc; I tested it using g++ 5.1.1 and same result; clang++ 3.5.0 compiled this code correctly. ```size()``` method should be constexpr regardless of type stored in std::array. – Patryk Obara Feb 12 '16 at 13:44

1 Answers1

2

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

jjaguayo
  • 109
  • 4