std::apply and constant expression?
Asked Answered
B

3

9

I tried code below in Wandbox:

#include <array>
#include <iostream>
#include <tuple>
#include <typeinfo>
#include <functional>
#include <utility>


int main()
{
    constexpr std::array<const char, 10> str{"123456789"};
    constexpr auto foo = std::apply([](auto... args) constexpr { std::integer_sequence<char, args...>{}; } , str);
    std::cout << typeid(foo).name();
}

and the compiler told me that args... are not constant expression. What's wrong?

Blowfish answered 12/11, 2016 at 4:55 Comment(2)
Unless this has changed in C++1z, you cannot have constexpr function parameters. That is, every function must assume it may be called with runtime parameters, and then your lambda doesn't make sense.Inception
@Inception What a pity…Blowfish
F
4

All constexpr functions must be valid both constexpr and not, even if marked constexpr.

There is a proposal for a constexpr literal that passed characters as non type template parameters. Then "hello"_bob could expand directly to a parameter pack.

Another approach is you can pass std::integral_constant<T, t> to the lambda through some mechanism, like my indexer. Then converting to T is constexpr even tho the variable is not. This does not help you with "hello" to a sequence.

Fussy answered 12/11, 2016 at 9:28 Comment(0)
W
7

Function parameters cannot be labeled constexpr. As such, you cannot use them in places that require constant expressions, like non-type template arguments.

To do the kind of thing you're trying to do would require some kind of compile-time string processing, based around template arguments.

Wappes answered 12/11, 2016 at 5:30 Comment(0)
C
5

What you want can be done without std::apply:

#include <array>
#include <iostream>
#include <tuple>
#include <typeinfo>
#include <functional>
#include <utility>
#include <type_traits>

template <std::size_t N, class = std::make_index_sequence<N>>
struct iterate;

template <std::size_t N, std::size_t... Is>
struct iterate<N, std::index_sequence<Is...>> {
    template <class Lambda>
    constexpr auto operator()(Lambda lambda) {
        return lambda(std::integral_constant<std::size_t, Is>{}...);
    }
};

int main()
{
    constexpr std::array<const char, 10> str{"123456789"};
    constexpr auto foo = iterate<str.size()>{}([](auto... is) constexpr { return std::integer_sequence<char, str[is]...>{}; });
    std::cout << typeid(foo).name();
}

[live demo]

Chessboard answered 12/11, 2016 at 12:17 Comment(14)
I actually now think it shouldn't but not sure yet... :/Chessboard
I'm more concerned about using arguments in a constant expression. As per the other answers I'd have expected it to ensure this is also callable with runtime arguments.Inception
Though I don't have such doubts with this code. It's a clever idea!Inception
I think this one is actually ok. std::integral_constant has its overload of constexpr operator T() allowing it to be used in constexpr context. Or am I mising something?Chessboard
The question if str declared in main can be used in context of lambda is on the other hand still opened..Chessboard
You seem to be right about integral constants. eel.is/c++draft/expr.prim.lambda#10 and eel.is/c++draft/expr.prim.lambda#13 suggest that your code is perfectly okayInception
Nice founding! Thank you!Chessboard
You can even make "factory" for it, but currently gcc crashed on this melpon.org/wandbox/permlink/JRvLX98vakSP1k2k .Bondstone
@Orient Nice test for compiler you've made... Have you watched what syntax element caused compiler crash was it constexpr lambda or auto template parameter...?Chessboard
Namely auto const & template parameter. If it slightly modified to be template< std::size_t size, char const (& value)[size] >, then all is OK, but then I need to provide size parameter manually.Bondstone
@Orient one word - I've just noticed you used gcc clang extension on string literal, while I'm opened on that, some people would probably like to wait for when it become official c++ feature...Chessboard
@Chessboard I submitted the bug, but it's status is not changed yet to resolved. That extension is quite old. Don't know is there a proposal for it.Bondstone
@Chessboard Which wandbox compiled fine? This still can't.Bondstone
Let us continue this discussion in chat.Chessboard
F
4

All constexpr functions must be valid both constexpr and not, even if marked constexpr.

There is a proposal for a constexpr literal that passed characters as non type template parameters. Then "hello"_bob could expand directly to a parameter pack.

Another approach is you can pass std::integral_constant<T, t> to the lambda through some mechanism, like my indexer. Then converting to T is constexpr even tho the variable is not. This does not help you with "hello" to a sequence.

Fussy answered 12/11, 2016 at 9:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.