On 27/06/19 19:07 -0400, Ed Smith-Rowland wrote:
On 6/27/19 1:06 PM, Ville Voutilainen wrote:
On Thu, 27 Jun 2019 at 19:55, Ed Smith-Rowland via libstdc++
<libstd...@gcc.gnu.org> wrote:
I don't think this will work in a constant expression:

?? /// Assign @p __new_val to @p __obj and return its previous value.
?? template <typename _Tp, typename _Up = _Tp>
+?????? _GLIBCXX20_CONSTEXPR
?????? inline _Tp
?????? exchange(_Tp& __obj, _Up&& __new_val)
?????? { return std::__exchange(__obj, std::forward<_Up>(__new_val)); }

Because std::__exchange hasn't been marked constexpr. The test passes
because it doesn't call it in a context that requires constant
evaluation:

??const auto x = std::exchange(e, pi);
Derp.
I see the same problem in other tests too:

+?? constexpr std::array<int, 12> car{{0, 1, 2, 3, 4, 5, 6, 6, 8, 9, 9,
11}};
+
+?? const auto out0x = std::adjacent_find(car.begin(), car.end());
+
+?? const auto out1x = std::adjacent_find(car.begin(), car.end(),
+?????????????????????????????????????? std::equal_to<int>())
I will go through all the tests and make sure that some nontrivial
calculation is done that contributes to a final bool return.?? And clean
up the mess.?? I did this in chunk 2 but I guess I left a lot of chunk 1.
As was the case with the iterator patch, it's not a question of doing
a nontrivial calculation, but
a question of initializing a constexpr variable with the result. (Yeah
sure a non-type template
argument would also work but eurgh). Then, and only then, have we
proven that the code
works in a constexpr context. Initializing a const doesn't do that.
constinit would, but that's
C++20.

Ok, why isn't

?? static_assert(test());

a constexpr context?

It is, I missed that the array test does that at the bottom of the
file.


The std::exchange test passed originally because, unlike all the other algo tests I had neglected to call the test function in a constexpr context.

Note that constexpr_iter.c is this:

----

constexpr int
test()
{
?? constexpr std::array<int, 3> a1{{1, 2, 3}};
?? static_assert(1 == *a1.begin());
?? auto n = a1[0] * a1[1]* a1[2];
?? static_assert(1 == *a1.cbegin());

?? std::array<int, 3> a2{{0, 0, 0}};
?? auto a1i = a1.begin();
?? auto a1e = a1.end();
?? auto a2i = a2.begin();
?? while (a1i != a1e)
?????? *a2i++ = *a1i++;

?? return n;
}

void
run_test()
{
?? constexpr int n = test();
}

----

Things inside the function can, and in many cases for this capability must, be mutable.?? As long as the input and the final output is a literal we should be good, no?

Also when I assign returned iterators to constexpr I get:

/home/ed/gcc_git/libstdc++-v3/testsuite/25_algorithms/find_if_not/constexpr.cc:36: error: '(((std::array<int, 12>::const_pointer)(& ca0.std::array<int, 12>::_M_elems)) + 28)' is not a constant expression.

Yes, I tried adding that and got the same error, which is why I
thought the test had the same problem as the std::exchange one.

I'm not sure what causes that error, I'll take a look tomorrow.


Reply via email to