c++compilationc++-concepts

How to assert at compile time that a consteval function cannot be evaluated?


I am writing a function that for the purpose of this question is similar to std::format, in that std::format("{}") fails at compile-time, while std::format("{}", 1) compiles.

I want to make sure that no user calling my function can accidentally write std::format("{}"); instead, I want this to be a compile-time error, and this is the current behavior.

How do I ensure this behavior does not regress?

I have tried the following approach:

#include <format>

template<class T>
concept FormatMissingArgumentCompiles = requires { std::format("{}"); };

// This check incorrectly states that 'Format missing argument compiles'
static_assert(!FormatMissingArgumentCompiles<void>, "Format missing argument compiles");

int main() {}

However, it seems that std::format("{}") is a well-formed expression unless evaluated, and requires does not evaluate its arguments (https://en.cppreference.com/w/cpp/language/expressions.html#Potentially-evaluated_expressions).

Can I make requires evaluate (at least partially) its std::format_string arguments as it would at compile time of regular code to see that construction of std::format("{}") is ill-formed?

Update: three comments and an answer indicate to me that my question wasn't super clear. I am not looking for a way to make compilation fail if the user writes std::format("{}") - I have that. I want compilation to fail if writing std::format("{}") would not make compilation fail.


Solution

  • Not sure it is what you want, but, you can use template class to force constexpr evaluation. std::format_string is the class with consteval constructor to evaluate:

    template<class... Ts>
    concept FormatMissingArgumentCompiles = requires {
        std::array<int, (std::format_string<Ts...>("{}"), 42)>{};
    };
    
    static_assert(!FormatMissingArgumentCompiles<>, "Format missing argument compiles");
    static_assert(FormatMissingArgumentCompiles<int>);
    static_assert(FormatMissingArgumentCompiles<int, int>); // std::format("{}", 1, 2) is valid
    

    Demo