3

I'd like to accomplish something like the following:

#define FOO(bar, ...) \
  static_assert(bar == "foo" || bar == "bazz", "Invalid value for bar") \
  ...

In other words, I'd like to check at compile time that the value given to the macro is one of the allowed ones. What is the cleanest way for doing a compile time string comparison when comparing against strings of variable length?

eof
  • 153
  • 2
  • 8
  • 1
    I would say the cleanest way is "don't use a macro"... With C++17 you have a lot of compile-time facilities at your disposal. – Max Langhof Nov 21 '19 at 08:54
  • @MaxLanghof Do you have a template sketch? – Peter - Reinstate Monica Nov 21 '19 at 08:54
  • 1
    Also, since you ask "what's the cleanest way": Do you have a dirty one? – Peter - Reinstate Monica Nov 21 '19 at 08:55
  • You may be interested in [this post](https://stackoverflow.com/questions/2335888/how-to-compare-strings-in-c-conditional-preprocessor-directives) and the answers. I think it's a dup. (I found that by googling -- hint, hint.) – Peter - Reinstate Monica Nov 21 '19 at 08:58
  • this is almost the same question https://stackoverflow.com/questions/27490858/how-can-you-compare-two-character-strings-statically-at-compile-time – 463035818_is_not_an_ai Nov 21 '19 at 08:59
  • This is basically used for some logging stuff where I need the source line number and file of the caller. To my knowledge this isn't doable without using macros. – eof Nov 21 '19 at 09:00
  • For the dirty one... I can compare each character one at a time, e.g. something like (#bar)[0] == "f" || ... || (sizeof(#bar) > 4 && (#bar)[3] == "z") || sizeof(#bar) < 6)) – eof Nov 21 '19 at 09:06
  • 1
    Why don't use `enum` instead of string? – Jarod42 Nov 21 '19 at 09:09
  • For not using an enum: I don't want to pollute the namespace and using an enum class would require more typing by the macro user. – eof Nov 21 '19 at 09:17
  • I don't think "more typing" is sufficient reason not to use an enum. The benefits outweigh the drawbacks in my opinion – Indiana Kernick Nov 21 '19 at 09:22

1 Answers1

3

You could use string views.

#include <string_view>

using namespace std::string_view_literals;

// Note the sv after the string
#define FOO(bar, ...) \
  static_assert(bar == "foo"sv || bar == "bazz"sv, "Invalid value for bar") \
  ...

The expression "foo"sv invokes a literal operator. It constructs a std::string_view from "foo". std::string_view has overloaded == operators for comparing with strings. These overloaded operators are constexpr which means that they can be evaluated at compile time.

Indiana Kernick
  • 5,041
  • 2
  • 20
  • 50
  • Didn't know about the "sv" trick! This was exactly the kind of thing I was looking for. – eof Nov 21 '19 at 09:07