将 constexpr 更改为 consteval 会导致 MSVC 中出现无法理解的错误消息。编译器错误或有问题的代码?
Changing constexpr to consteval results in unintelligible error message in MSVC. Compiler bug or questionable code?
我有以下模板/编译时实用程序辅助函数。当一切都是 constexpr
时,它在所有三个编译器(MSVC、GCC、clang)中工作正常,但是将一些位更改为 consteval
会导致 MSVC 中出现奇怪的错误。我想尽可能地将我所有的 constexpr
机器迁移到 consteval
,这个问题没有帮助。
#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);
错误信息是:
<source>(52): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'std::optional<size_t>'
<source>(52): note: Invalid aggregate initialization
我根本没有看到 optional
的任何聚合初始化。我的问题是:您认为这是 MSVC 中的错误,还是我的代码有问题?
P. S. 删除 optional
并返回 size_t
可以消除错误,但我确实需要一种方法来说明“包中不存在该类型”而不会出现编译错误。 std::optional
似乎非常适合这个语义。
删除所有内脏后会发生同样的错误。
#include <optional>
[[nodiscard]] consteval std::optional<size_t> index_for_type() noexcept
{
return 1;
}
static_assert(index_for_type() == 2);
这让我相信微软的std::optional
还没有consteval
准备好。
我有以下模板/编译时实用程序辅助函数。当一切都是 constexpr
时,它在所有三个编译器(MSVC、GCC、clang)中工作正常,但是将一些位更改为 consteval
会导致 MSVC 中出现奇怪的错误。我想尽可能地将我所有的 constexpr
机器迁移到 consteval
,这个问题没有帮助。
#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);
错误信息是:
<source>(52): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'std::optional<size_t>'
<source>(52): note: Invalid aggregate initialization
我根本没有看到 optional
的任何聚合初始化。我的问题是:您认为这是 MSVC 中的错误,还是我的代码有问题?
P. S. 删除 optional
并返回 size_t
可以消除错误,但我确实需要一种方法来说明“包中不存在该类型”而不会出现编译错误。 std::optional
似乎非常适合这个语义。
删除所有内脏后会发生同样的错误。
#include <optional>
[[nodiscard]] consteval std::optional<size_t> index_for_type() noexcept
{
return 1;
}
static_assert(index_for_type() == 2);
这让我相信微软的std::optional
还没有consteval
准备好。