K. Koovalsky
K. Koovalsky

Reputation: 606

Pass reference to a static storage cstyle array from on constexpr function to another constexpr function

I can't pass a global cstyle array to a constexpr function for C++14. I have an array like this:

static const char t[] = "sometext";

And I have two functions:

template <typename T, typename U, std::size_t N>
constexpr static auto count(T (&arr)[N], const U &val)
{
    auto cnt = 0;
    auto it(std::cbegin(arr));
    while (it != std::cend(arr))
    {
        if (*it == val)
            cnt++;
        it++;
    }
    return cnt;
}

template <typename T, std::size_t N> constexpr static auto count_wrapper(T (&arr)[N])
{
    constexpr auto num_elems(count(arr, ','));
    return num_elems;
}

When I call the first function like that:

std::cout << count(t, ',') << std::endl;

I can compile the code and run it, but when I call the second function like that:

count_wrapper(t);

I get an error:

main.cpp: In instantiation of ‘constexpr auto t(T (&)[N]) [with T = const char; long unsigned int N = 46]’: main.cpp:51:53: required from here main.cpp:40:35: in constexpr expansion of ‘count((* & arr), ',')’ main.cpp:40:20: error: ‘arr’ is not a constant expression constexpr auto num_elems(count(arr, ',') + 1);

Upvotes: 0

Views: 109

Answers (2)

Nick
Nick

Reputation: 10539

What is num_elems? If it is fancy initialization, then whole code can be "rewritten" as this:

#include <cstdint>
#include <iterator>

const char t[] = "sometext";

template <typename T, typename U, std::size_t N>
constexpr auto count(const T (&arr)[N], const U &val)
{
    std::size_t cnt = 0;

    for(auto it = std::begin(arr); it != std::end(arr); ++it)
    {
        if (*it == val)
            cnt++;
    }

    return cnt;
}

template <typename T, std::size_t N> 
constexpr auto count_wrapper(const T (&arr)[N])
{
    auto const num_elems = count(arr, 'e');
    return num_elems;
}

int main()
{
    constexpr auto x = count_wrapper(t);
    return static_cast<int>(x);
}

This compiles and run correctly. I changed , to e so it counts some elements. I also changed while to for loop. Also I did changed auto cnt to std::size_t cnt.

Note because of auto, the type of x in main is size_t.

https://gcc.godbolt.org/z/3cdTzr

Upvotes: 0

Jarod42
Jarod42

Reputation: 218098

Arguments are not / cannot be constexpr. (constexpr functions might be used in non-constexpr context).

Notice that std::cout << count(t, ',') << std::endl; might be computed at runtime. you would need

constexpr auto c = count(t, ',');
std::cout << c << std::endl;

to have constexpr evaluation guarantee.

You might wrap the value in a type if appropriate.

template <typename T, T ... cs, typename U>
constexpr static auto count(std::integer_sequence<T, cs...>, const U &val)
{
    const T arr[] = {cs...};
    auto cnt = 0;
    auto it(std::cbegin(arr));
    while (it != std::cend(arr))
    {
        if (*it == val)
            cnt++;
        it++;
    }
    return cnt;
}

auto sometext = std::integer_sequence<char,
                                      's', 'o', 'm', 'e', 't', 'e', 'x', 't' /*, '\0'*/>;

constexpr auto num_elems(count(sometext, ','));

Upvotes: 0

Related Questions