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?

Sergey
  • 7,985
  • 4
  • 48
  • 80
Cu2S
  • 667
  • 1
  • 5
  • 21
  • 7
    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. – krzaq Nov 12 '16 at 05:05
  • @krzaq What a pity… – Cu2S Nov 12 '16 at 05:16

3 Answers3

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.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
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]

W.F.
  • 13,888
  • 2
  • 34
  • 81
  • I actually now think it shouldn't but not sure yet... :/ – W.F. Nov 12 '16 at 12:52
  • 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. – krzaq Nov 12 '16 at 12:57
  • Though I don't have such doubts with [this](http://melpon.org/wandbox/permlink/jjmSjmwHlZ8rec5L) code. It's a clever idea! – krzaq Nov 12 '16 at 12:59
  • 1
    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? – W.F. Nov 12 '16 at 13:03
  • The question if `str` declared in `main` can be used in context of lambda is on the other hand still opened.. – W.F. Nov 12 '16 at 13:05
  • 1
    You seem to be right about integral constants. http://eel.is/c++draft/expr.prim.lambda#10 and http://eel.is/c++draft/expr.prim.lambda#13 suggest that your code is perfectly okay – krzaq Nov 12 '16 at 13:11
  • Nice founding! Thank you! – W.F. Nov 12 '16 at 13:13
  • 1
    You can even make "factory" for it, but currently gcc crashed on this http://melpon.org/wandbox/permlink/JRvLX98vakSP1k2k . – Tomilov Anatoliy Nov 12 '16 at 22:06
  • @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...? – W.F. Nov 12 '16 at 22:14
  • 1
    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. – Tomilov Anatoliy Nov 12 '16 at 22:40
  • @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... – W.F. Nov 13 '16 at 11:37
  • 1
    @W.F. 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. – Tomilov Anatoliy Nov 13 '16 at 13:07
  • @W.F. Which wandbox compiled fine? [This](http://melpon.org/wandbox/) still can't. – Tomilov Anatoliy Nov 13 '16 at 13:10
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/127990/discussion-between-w-f-and-orient). – W.F. Nov 13 '16 at 13:14
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.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524