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.
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.