c++arraysc++20constexprconsteval

constant expression error when consteval function called from another


I am trying to use the return value from a consteval function UniqueSize() inside another consteval function UniqueArra to declare an array, but this results in a compiler error saying that UniqueSize() is not a constant expression.

However, if I use UniqueSize() inside main() and use its return value to declare an array the compiler just accepts it. Why is this happening ? Can someone please explain the difference of constant expressions in these contexts ?

Thank you in advane.

See the code below. https://godbolt.org/z/nd18WE8M5

template <typename... Args>
consteval auto UniqueSize(Args&&... args)
{
    std::vector v{std::forward<Args>(args)...};
    std::sort(v.begin(), v.end());
    auto newEnd = std::unique(v.begin(), v.end());
    return std::distance(v.begin(), newEnd);
}

template <typename... Args>
consteval auto UniqueArray(Args&&... args)
{
    // Calling UniqueSize to determine the size of the array returned
    constexpr auto sz = UniqueSize(std::forward<Args>(args)...);
    std::array<int, sz> arr{};

    std::vector v{std::forward<Args>(args)...};
    std::sort(v.begin(), v.end());
    auto newEnd = std::unique(v.begin(), v.end());
    std::copy(v.begin(), v.end(), arr.begin());
    return arr;
}

int main()
{
    // This compiles fine
    constexpr auto sz = UniqueSize(2, 3, 4, 4, 5, 5);
    static_assert(sz == 4);
    std::array<int, sz> array{};

    // This gives an error complaining that `sz` inside UniqueArray is not a constant expression. 
    // auto arr = UniqueArray(2, 3, 4, 4, 5, 5);
}

Solution

  • As explained in this SO post, parameters of consteval function are not considered consteval.

    To allow what you are aiming for, you need to move the parameters to be template paramaters. Something like this should work:

    template <auto... args>
    consteval auto UniqueBigArray() {
        using TYPE = std::common_type_t<decltype(args)...>;
        std::array<TYPE, sizeof...(args)> arr{args...};
        std::sort(arr.begin(), arr.end());
        auto last = std::unique(arr.begin(), arr.end());
        return std::pair {arr, std::distance(arr.begin(), last)};
    }
    
    template <auto... args>
    consteval auto UniqueSize() {
        return UniqueBigArray<args...>().second;
    }
    
    template <auto... args>
    consteval auto UniqueArray() {
        constexpr auto p = UniqueBigArray<args...>();
        std::array<typename decltype(p.first)::value_type, p.second> arr{};
        std::copy(p.first.begin(), p.first.begin() + p.second, arr.begin());
        return arr;
    }
    
    int main() {
        constexpr auto sz = UniqueSize<2, 3, 4, 4, 5, 5>();
        static_assert(sz == 4);
    
        constexpr auto arr = UniqueArray<2, 3, 4, 4, 5, 5>();
        static_assert(arr == std::array{2, 3, 4, 5});
    
        constexpr auto arr2 = UniqueArray<3, 4.0, 4, 5, 5.5>();
        static_assert(arr2 == std::array{3.0, 4.0, 5.0, 5.5});
    }
    

    Code: https://godbolt.org/z/Gvh1xaY67