如何使consteval函数触发编译失败?——C++枚举数组查找函数的实现需求问询
Great question! Since you're working with a consteval function, we can leverage compile-time evaluation rules to trigger a failure directly inside the function without relying on external static_assert calls per usage. Here are a couple of robust approaches that fit your requirements:
Approach 1: static_assert with a constexpr lambda (clear error messages)
This method is the most readable, as it provides explicit error feedback and keeps all logic encapsulated within the function:
#include <array> enum class SomeEnum { Value1, Value2, Value3 }; template <size_t TSize> consteval size_t indexOf(SomeEnum someEnum, const std::array<SomeEnum, TSize> &arr) { // Compile-time check: does the enum exist in the array? constexpr bool enumExists = []() consteval { for (size_t i = 0; i < TSize; ++i) { if (arr[i] == someEnum) { return true; } } return false; }(); // Trigger compile error if the enum isn't found static_assert(enumExists, "Target SomeEnum value is not present in the provided array"); // Find and return the index (guaranteed to succeed due to static_assert) for (size_t i = 0; i < TSize; ++i) { if (arr[i] == someEnum) { return i; } } // Unreachable code, included only to satisfy compiler flow checks return 0; } // Test cases constexpr std::array<SomeEnum, 3> arr = {SomeEnum::Value1, SomeEnum::Value2, SomeEnum::Value3}; constexpr size_t validIdx = indexOf(SomeEnum::Value2, arr); // Compiles, returns 1 // constexpr size_t invalidIdx = indexOf(static_cast<SomeEnum>(99), arr); // Fails to compile with the static_assert message
Why this works:
- The
constevallambda ensures the existence check runs entirely at compile time - The
static_assertcondition is a compile-time constant, so it only triggers when the enum is missing - The error message is clear and directly tells you what went wrong
Approach 2: Call a deleted function (concise but less explicit)
If you want more concise code, you can trigger a compile failure by calling a deleted function in the "not found" branch. Since consteval requires all execution paths to be valid constant expressions, calling a deleted function will immediately halt compilation:
#include <array> enum class SomeEnum { Value1, Value2, Value3 }; template <size_t TSize> consteval size_t indexOf(SomeEnum someEnum, const std::array<SomeEnum, TSize> &arr) { for (size_t i = 0; i < TSize; ++i) { if (arr[i] == someEnum) { return i; } } // Trigger compile failure: call a deleted function static void compileTimeError() = delete; compileTimeError(); }
Notes:
- This method is shorter, but the compiler error message will be less intuitive (it'll only mention calling a deleted function, not the root cause of the enum missing)
- It still meets all your requirements: no external macros, all logic inside the function, and compile-time failure only
Why exceptions aren't a good fit here
You mentioned you can't use exceptions, which is the right call. While consteval functions can throw exceptions, the exception must be caught at compile time to be a valid constant expression. An uncaught exception will cause a compile error, but it's a clunky, indirect way to achieve your goal (and you explicitly excluded exceptions anyway).
Both approaches above keep your code clean, self-contained, and enforce the compile-time check you need.
内容的提问来源于stack exchange,提问作者nihohit

