Nestor
Nestor

Reputation: 747

How to pass a not explicitly string literal error message to a static_assert?

I have a few static asserts in different places in code.

static_assert(bool_constexpr_1, error_message);
...
static_assert(bool_constexpr_2, error_message);

And want all of them to share the same error_message.

The first solution is to copy-paste the message.

The second one is to #define the error_message.

Is there something better?

P.S. I expected static constexpr auto to work, yet it failed.

Upvotes: 3

Views: 1277

Answers (2)

JVApen
JVApen

Reputation: 11317

Your question sounds a lot like a variation: How to make static_assert block re-usable in template classes?

You have defined it a bit to generic, however, as you want to reuse the same 'error' message, I would assume that your check will also be similar. Let's use an example where you want to force inheritance:

 struct Interface {};
 struct Impl : Interface {};
 struct Other {};
 static_assert(std::is_base_of_v<Interface, Impl>, "Implementations should inherit from the interface. See document at ... for more details."); // Success
 static_assert(std::is_base_of_v<Interface, Other>, "Implementations should inherit from the interface. See document at ... for more details."); // Failure

Here, it might make sense to implement your own type trait. For example:

 template<typename T> using FrameworkInjectionRequirement = std::is_base_of<Interface, T>
 template<typename T> constexpr bool FrameworkInjectionRequirement_v = FrameworkInjectionRequirement<T>::value;

  static_assert(FrameworkInjectionRequirement_v<Impl>);

By doing this, you already gave a good name to what you try to check, which could be sufficient in order to use the terse version of static_assert instead, without needing an explanation.

Alternatively, you could wrap you assert into a struct:

template<typename T>
struct FrameworkInjectionRequirement {
    static_assert(std::is_base_of_v<Interface, T>, "Implementations should inherit from the interface. See document at ... for more details.");
};
constexpr static FrameworkInjectionRequirement<Impl> check{}; // Success
constexpr static FrameworkInjectionRequirement<Other> check{}; // Failure

By instantiating this zero-size struct at compile time (thanks to constexpr on the variable), the assert will be checked. Not only can you reuse the message into it, you again gave your check a good name. As a bonus, you can split up the different elements creating the boolean expression into it's distinct elements, which will assist you if one of them fails.

Upvotes: 3

NathanOliver
NathanOliver

Reputation: 180945

You either have to copy-paste the literal, or use the preprocessor. Per [dcl.dcl]/1 The grammar of static_assert is defined as

static_assert-declaration:
      static_­assert ( constant-expression ) ;
      static_­assert ( constant-expression , string-literal ) ;

So you either provide a string literal, or you don't. There is no other way to use it.

Upvotes: 5

Related Questions