0

I have the following template / compile-time utility helper functions. It works fine in all three compilers (MSVC, GCC, clang) when everything is constexpr, but changing a few bits to consteval results in an odd error in MSVC. I want to migrate all my constexpr machinery to consteval as much as possible, and this problem is not helping.

#include <optional> #include <tuple> #include <type_traits> template <auto v> struct value_as_type { static constexpr auto value = v; using type = decltype(value); consteval operator type() const noexcept { return v; } }; template <size_t First, size_t Last, typename Functor> consteval void consteval_for([[maybe_unused]] Functor&& f) noexcept { if constexpr (First < Last) { if constexpr (std::is_same_v<bool, std::invoke_result_t<Functor()>>) { if (f(value_as_type<First>{}) == false) return; } else f(value_as_type<First>{}); consteval_for<First + 1, Last>(std::forward<Functor>(f)); } } template <size_t index, typename... Args> using type_by_index = std::tuple_element_t<index, std::tuple<Args...>>; template <typename T, typename... Args> [[nodiscard]] consteval std::optional<size_t> index_for_type() noexcept { std::optional<size_t> index; consteval_for<0, sizeof...(Args)>([&index](auto i) { if (!index) // The index of the first occurrence is stored { if constexpr (std::is_same_v<T, type_by_index<static_cast<size_t>(i), Args... >> ) index = static_cast<size_t>(i); } }); return index; } static_assert(index_for_type<int, float, void, int, bool>() == 2); 

The error message is:

<source>(52): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'std::optional<size_t>' <source>(52): note: Invalid aggregate initialization 

I'm not seeing any aggregate initialization of the optional at all. And my question is: do you think it's a bug in MSVC, or is there something not right with my code?

P. S. Removing optional and just returning size_t removes the error, but I do need a way to say "the type is not present in the pack" without compilation error. std::optional seems the perfect fit for this semantically.

8
  • What line is the error? Commented Jul 13, 2021 at 22:06
  • @BenVoigt: the one with static_assert. Not helpful at all. Commented Jul 13, 2021 at 22:09
  • Have you tested the individual pieces (value_as_type, consteval_for, type_by_index) separately using static_assert? Commented Jul 13, 2021 at 22:12
  • value_as_type doesn't seem necessary or useful. Does it work if that layer is eliminated? Commented Jul 13, 2021 at 22:15
  • 1
    You might look into eliminating value_as_type in favor of std::integral_constant Commented Jul 13, 2021 at 22:45

1 Answer 1

3

The same error occurs with all the guts removed.

#include <optional> [[nodiscard]] consteval std::optional<size_t> index_for_type() noexcept { return 1; } static_assert(index_for_type() == 2); 

This leaves me to believe that Microsoft's std::optional is simply not consteval-ready yet.

Sign up to request clarification or add additional context in comments.

4 Comments

I see! It didn't occur to me this could be that simple. Looks like a compiler bug, right? Should I report this as such?
I would definitely report it. Whether it is a compiler problem or a library problem, the Visual C++ team will figure out where the fix needs to go.
@VioletGiraffe: I think I've reached the point of optimal simplification now. There is nothing even a little bit tricky left except consteval and a std::optional return type.
@VioletGiraffe: Turns out it does not even have to be a template function, you still get the error.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.