2

In the following code, I create an array of length 6 and initialize it with 1, 2 and 3 in the first 3 elements. Then I copy the first 3 elements to the last 3 elements. Then I print all the elements in order.

std::array<int, 6> bar = {1, 2, 3};

int main(){
    // Copy the first 3 elements to the last 3 elements
    std::copy(bar.begin(), bar.end() - 3, bar.end() - 3);

    // Print all the elements of bar
    for(auto& i: bar) std::cout << i << std::endl;
}

It works fine, but when I try to make the array constexpr it no-longer compiles:

constexpr std::array<int, 6> bar = {1, 2, 3};

int main(){
    // Copy the first 3 elements to the last 3 elements
    std::copy(bar.begin(), bar.end() - 3, bar.end() - 3); // Won't compile!

    // Print all the elements of bar
    for(auto& i: bar) std::cout << i << std::endl;
}

Compiling with g++ -std=c++14 main.cpp -o main I get the following error message:

/usr/include/c++/5/bits/stl_algobase.h: In instantiation of ‘_OI std::__copy_move_a(_II, _II, _OI) [with bool _IsMove = false; _II = const int*; _OI = const int*]’:
/usr/include/c++/5/bits/stl_algobase.h:438:45:   required from ‘_OI std::__copy_move_a2(_II, _II, _OI) [with bool _IsMove = false; _II = const int*; _OI = const int*]’
/usr/include/c++/5/bits/stl_algobase.h:471:8:   required from ‘_OI std::copy(_II, _II, _OI) [with _II = const int*; _OI = const int*]’
main.cpp:115:53:   required from here
/usr/include/c++/5/bits/stl_algobase.h:402:44: error: no matching function for call to ‘std::__copy_move<false, true, std::random_access_iterator_tag>::__copy_m(const int*&, const int*&, const int*&)’
                        _Category>::__copy_m(__first, __last, __result);
                                            ^
/usr/include/c++/5/bits/stl_algobase.h:373:9: note: candidate: template<class _Tp> static _Tp* std::__copy_move<_IsMove, true, std::random_access_iterator_tag>::__copy_m(const _Tp*, const _Tp*, _Tp*) [with _Tp = _Tp; bool _IsMove = false]
         __copy_m(const _Tp* __first, const _Tp* __last, _Tp* __result)
         ^
/usr/include/c++/5/bits/stl_algobase.h:373:9: note:   template argument deduction/substitution failed:
/usr/include/c++/5/bits/stl_algobase.h:402:44: note:   deduced conflicting types for parameter ‘_Tp’ (‘int’ and ‘const int’)
                        _Category>::__copy_m(__first, __last, __result);

I don't understand this error message at all. Is std::copy not constexpr? If it isn't, it should be, right? Does my code would work if std::copy was constexpr?

9
  • 2
    If the array is const, you can't change it. Commented Jan 11, 2017 at 20:34
  • I do not have much experience with new C++ feature but it does not make sense to declare an array constexpr if you want to modify it afterwards. Either, the array is constant or not. Commented Jan 11, 2017 at 20:39
  • @latedeveloper How to I make stuff at compiletime that isn't 'const' then? Commented Jan 11, 2017 at 20:44
  • @WillyGoat - exactly... what do you want make at compile time? Duplicate a list of values in an array? Commented Jan 11, 2017 at 20:46
  • @Willy I don't understand what you are asking. Commented Jan 11, 2017 at 20:47

2 Answers 2

5

You should make a constexpr function. constexpr imply const, but not inside the scope of a constexpr function.

constexpr auto get_bar() {
    std::array<int, 6> bar = {1, 2, 3, 0, 0, 0};

    copy(bar.begin(), bar.end() - 3, bar.end() - 3);

    return bar;
}

However, you will need to write your own version of copy because it's not marked as constexpr in the standard library.

Changing the value of a compile time array does not make sense, it's the same thing as asking the compiler to change the type of a variable at runtime. The compiler don't even exist during runtime. However, a constexpr function is executed by the compiler, so it's still make sense to ask it to mutate values. This is why the code above make sense.

Note that most of std::array accessors are not constexpr until C++17.

Sign up to request clarification or add additional context in comments.

4 Comments

Also note that std::array<T, n>::begin(), std::array<T, n>::end() and all other accessors are only constexpr since C++17.
@yurikilochek Indeed, I'll add that to the answer.
Thanks. I really appreciate your second sentence. I've been confused about the const-ness of constexpr. To me it still doesn't make sense that something has to be const if you want it to be evaluated at compiletime. What if you need to precompute a huge array that gets altered at runtime?
@WillyGoat I added a paragraph to the answer. Hope it helps.
3

constexpr imply const.

Your std::copy try to modify a const variable.

--- EDIT ---

The OP ask

I'm implementing something that uses a very large array of precomputed values which wrap around once. I can't do this without printing out values and copy-pasting them into my code?

What about something as follows?

#include <array>
#include <iostream>

template <int ... I>
struct foo
 { std::array<int, 2U*sizeof...(I)> bar { { I..., I... } }; };

int main()
 {
   foo<2, 3, 5, 7, 11, 13> v;

   for ( auto const & i : v.bar )
      std::cout << i << ", ";

   // the for print 2, 3, 5, 7, 11, 13, 2, 3, 5, 7, 11, 13,

   std::cout << std::endl;
 }

5 Comments

How do get around that? I don't mind the array being const at runtime, but I'd like to be able to edit it programmatically at compiletime.
Don't make it const. Why would you make it const if you want to change it?
@WillyGoat - a const (constexpr) variable can only be initialized; you have to insert all values in initialization; and if you want to do something at compiletime, has to be constexpr or templape arguments.
I appreciate the edit. That's some crazy c++, but I like Guillaume's solution the most. Thanks! :)
@WillyGoat - you're wellcome :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.