Checking that macro parameter is one of the allowed ones? - c++

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?

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.

Related

Is it possible to convert a macro with stringizing operator to a constexpr?

I have written the following macro to mimic C#'s nameof operator but in C++/CLI:
#define nameof(x) (#x)
if (info == nullptr)
throw gcnew ArgumentNullException(nameof(info));
I have tried to convert this macro to a constexpr:
Either of these are wrong, they return the content of ToString:
template <typename T>
constexpr auto NAMEOF1(T value)
{
return """" + value + """";
}
template <typename T>
constexpr auto NAMEOF2(T value)
{
return System::String::Format("{0}", value);
}
Third attempt, using the typeid keyword:
template <typename T>
constexpr auto NAMEOF3(T value)
{
return gcnew System::String(typeid(value).name());
}
But it fails with the following error:
error C3185: 'typeid': used on managed type 'T', use 'T::typeid' instead
In short, not as easy as it sounds.
Question:
Is it possible to convert this nameof macro to a constexpr ?
(or should I just stick to good old #define ?)
No, it is not possible to obtain the name of an object in C++ in a constexpr function. constexpr functions are still able to be called at runtime, and at runtime, there is no possibility for this kind of reflection. Indeed, reflection in C++ in general is extremely limited. Without macros, your reflection abilities are limited to testing for the existence of and type of members using dirty and unintuitive template trickery, but nothing that returns a name as a string. Also be aware that as soon as an argument is passed to a function like NAMEOF1, the name of that argument will always be "value". There is no way to query the scope of the caller for the name or expression that was passed.
You should stick with your solution:
#define nameof(x) (#x)
This is of course, also a very limiting solution. This will simply turn the expression x into a string perfectly verbatim, and has no concept of different entities and scoping like nameof in C#.
I say this coming from a non-managed C++ background. From the error message you receive, it's clear that managed C++ has interesting effects on typeid. Perhaps somebody who knows more about C++/CLI can enlighten me or give a better answer.
Alternatively, if this sort of null-check is a frequent pattern, you could wrap that into a more concise macro. For example:
define THROW_IF_NULL(x) \
if ((x) == nullptr){ \
throw gcnew ArgumentNullException(#x); \
}
Example usage:
void process_info(Info* info){
THROW_IF_NULL(info)
// --snip--
}
On a side not, I'm not sure what you expect this to do:
return """" + value + """";
but if my understanding is correct, the expression """" will be parsed as two empty string literals ("", ""), which, because they appear side-by-side, are appended by the preprocessor into a single empty string literal. You can thus replace """" with "" to achieve the same effect. But perhaps you wanted something else?

c++ macro recognizing tokens as arguments

So, it's been a while since I have written anything in C++ and now I'm working on a project using C++11 and macros.
I know that by using the stringify operator I can do this:
#define TEXT(a) #a //expands to "a"
How am I supposed to use the preprocessor for recognizing the tokens like + and * to do this:
#define TEXT(a)+ ??? //want to expand to "a+"
#define TEXT(a)* ??? //want to expand to "a*"
when the input has to be in that syntax?
I have tried doing that:
#define + "+"
but of course it doesn't work. How can I make the preprocessor recognize those tokens?
NOTE:
This is actually part of a project for a small language that defines and uses regular expressions, where the resulting string of the macros is to be used in a regex. The syntax is given and we have to use it as it is without making any changes to it.
eg
TEXT(a)+ is to be used to make the regular expression: std::regex("a+")
without changing the fact that TEXT(a) expands to "a"
First,
#define TEXT(a) #a
doesn't “convert to "a"”. a is just a name for a parameter. The macro expands to a string that contains whatever TEXT was called with. So TEXT(42 + rand()) will expand to "42 + rand()". Note that, if you pass a macro as parameter, the macro will not be expanded. TEXT(EXIT_SUCCESS) will expand to "EXIT_SUCCESS", not "0". If you want full expansion, add an additional layer of indirection and pass the argument to TEXT to another macro TEXT_R that does the stringification.
#define TEXT_R(STUFF) # STUFF
#define TEXT(STUFF) TEXT_R(STUFF)
Second, I'm not quite sure what you mean with TEXT(a)+ and TEXT(a)*. Do you want, say, TEXT(foo) to expand to "foo+"? I think the simplest solution in this case would be to use the implicit string literal concatenation.
#define TEXT_PLUS(STUFF) # STUFF "+"
#define TEXT_STAR(STUFF) # STUFF "*"
Or, if you want full expansion.
#define TEXT_R(STUFF) # STUFF
#define TEXT_PLUS(STUFF) TEXT_R(STUFF+)
#define TEXT_STAR(STUFF) TEXT_R(STUFF*)
Your assignment is impossible to solve in C++. You either misunderstood something or there’s an error in the project specification. At any rate, we’ve got a problem here:
TEXT(a)+ is to be used to make the regular expression: std::regex("a+") without changing the fact that TEXT(a) expands to "a" [my emphasis]
TEXT(a) expands to "a" — meaning, we can just replace TEXT(a) everywhere in your example; after all, that’s exactly what the preprocessor does. In other words, you want the compiler to transform this C++ code
"a"+
into
std::regex("a+")
And that’s simply impossible, because the C++ preprocess does not allow expanding the + token.
The best we can do in C++ is use operator overloading to generate the desired code. However, there are two obstacles:
You can only overload operators on custom types, and "a" isn’t a custom type; its type is char const[2] (why 2? Null termination!).
Postfix-+ is not a valid C++ operator and cannot be overloaded.
If your assignment had just been a little different, it would work. In fact, if your assignment had said that TEXT(a)++ should produce the desired result, and that you are allowed to change the definition of TEXT to output something other than "a", then we’d be in business:
#include <string>
#include <regex>
#define TEXT(a) my_regex_token(#a)
struct my_regex_token {
std::string value;
my_regex_token(std::string value) : value{value} {}
// Implicit conversion to `std::regex` — to be handled with care.
operator std::regex() const {
return std::regex{value};
}
// Operators
my_regex_token operator ++(int) const {
return my_regex_token{value + "+"};
}
// more operators …
};
int main() {
std::regex x = TEXT(a)++;
}
You don't want to jab characters onto the end of macros.
Maybe you simply want something like this:
#define TEXT(a, b) #a #b
that way TEXT(a, +) gets expanded to "a" "+" and TEXT(a, *) to "a" "*"
If you need that exact syntax, then use a helper macro, like:
#define TEXT(a) #a
#define ADDTEXT(x, y) TEXT(x ## y)
that way, ADDTEXT(a, +) gets expanded to "a+" and ADDTEXT(a, *) gets expanded to "a*"
You can do it this way too:
#define TEXT(a) "+" // "a" "+" -> "a+"
#define TEXT(a) "*" // "a" "*" -> "a*"
Two string literals in C/C++ will be joined into single literal by specification.

Macros to return defined(X) as true or false

I'd like a sequence of macros to replace the following code
#ifdef FOO
return true;
#else
return false;
#endif
with something like
return MAGICLY_EXPANDING_IFDEFINED_MACRO(FOO);
As you can guess, there are a lot of FOOs, enough that shrinking 4 lines to 1 would be cool. But really it would be replacing a monster switch statement with one line.
In C++, the behavior of defined is specified only for conditional inclusion (#if and #elif). So you cannot use it in any other way.
(The relevant rules are found in section 16.1 of the Standard)
But, if you want to detect macros that specifically are #define to the empty string, you don't need defined(), you can do this:
#include <iostream>
/* this matches */
#define FOO
/* this will not */
#undef BAZ
/* nor will these */
#define BAR 0
//#define BAR 1
#define STRINGIZE(x) (#x)
#define EXPAND_IF_DEFINED(y) (!*STRINGIZE(y))
int main()
{
std::cout << +EXPAND_IF_DEFINED(FOO) << '\n'
<< +EXPAND_IF_DEFINED(BAR) << '\n'
<< +EXPAND_IF_DEFINED(BAZ) << '\n';
}
Warning, the -D option will not be an empty string. To handle that case, you could use something like
#define IS_MACRO_DEFINED_OR_ONE(y) (!*STRINGIZE(y) || '1'==*STRINGIZE(y))
An even stronger test would be
#define IS_MACRO_DEFINED_NOT_TO_ITSELF(y) strcmp(#y, STRINGIZE(y))
Since literals are compile-time constants, the compiler will probably optimize that strcmp call during compilation to a constant true or false. You could also make a constexpr version of strcmp to use.
For simple defines like #define FOO or #define FOO 1 the below macros will work well, but much more universal solution is in #BenVoigt 's answer.
#define MAGICLY_EXPANDING_IFDEFINED_MACRO_I(X) (#X[0] == 0 || #X[0] == '1')
#define MAGICLY_EXPANDING_IFDEFINED_MACRO(X) MAGICLY_EXPANDING_IFDEFINED_MACRO_I(X)
DEMO
Q&A section
How it works?
That weird #-something stringifies either the value of define, or the define name itself (if one is not defined). As such, for defined FOO (with empty content) the compiler ends up with condition:
(""[0] == 0 || ""[0] == '1')
while for undefined FOO the condition is:
("FOO"[0] == 0 || "FOO"[0] == '1')
That == 0 part matches the \0 character ending each raw string literal (even that empty one ""), while the == '1' condition is there in case someone defines value 1, like in #define FOO 1
Macros are generally a bad route. What are you trying to accomplish? Something like this would work:
//Stash this away in a header file
#ifndef FOO
#define RETURN false
#else
#define RETURN true
#endif
return RETURN;

For identical static_assert messages, should I rely on MACROS?

static_assert has the following syntax, which states that a string literal is required.
static_assert ( bool_constexpr , string literal );
Since an instance of a string CAN'T be observed at compile time, the following code is invalid:
const std::string ERROR_MESSAGE{"I assert that you CAN NOT do this."};
static_assert(/* boolean expression */ ,ERROR_MESSAGE);
I have static asserts all over my code, which say the same error message.
Since a string literal is required, would it be best to replace all the repetitive string literals with a MACRO, or is there a better way?
// Is this method ok?
// Should I hand type them all instead?
// Is there a better way?
#define _ERROR_MESSAGE_ "danger"
static_assert(/* boolean expression 1*/ ,_ERROR_MESSAGE_);
//... code ...
static_assert(/* boolean expression 2*/ ,_ERROR_MESSAGE_);
//... code ...
static_assert(/* boolean expression 3*/ ,_ERROR_MESSAGE_);
In C++ you should not define a constant as a macro. Define it as a constant. That's what constants are for.
Also, names beginning with underscore followed by uppercase letter, such as your _ERROR_MESSAGE_, are reserved to the implementation.
That said, yes, it's good idea to use a macro for static asserts, both to ensure a correct string argument and to support compilers that possibly don't have static_assert, but this macro is not C style constant: it takes the expression as argument, and provides that expression as the string message.
Here is my current <static_assert.h>:
#pragma once
// Copyright (c) 2013 Alf P. Steinbach
// The "..." arguments permit template instantiations with "<" and ">".
#define CPPX_STATIC_ASSERT__IMPL( message_literal, ... ) \
static_assert( __VA_ARGS__, "CPPX_STATIC_ASSERT: " message_literal )
#define CPPX_STATIC_ASSERT( ... ) \
CPPX_STATIC_ASSERT__IMPL( #__VA_ARGS__, __VA_ARGS__ )
// For arguments like std::integral_constant
#define CPPX_STATIC_ASSERT_YES( ... ) \
CPPX_STATIC_ASSERT__IMPL( #__VA_ARGS__, __VA_ARGS__::value )
As you can see there are some subtleties involved even when the compiler does have static_assert.

Compile-time assert for string equality

Is this possible to do using templates?
There are two string constants. They come from defines in different modules. They must be equal, or I shall raise compile-time error if they are not equal. Can I do this using templates?
#define MY_STRING "foo"
CompileAssertIfStringsNotEqual(MY_STRING, HIS_STRING);
P.S. I was deluded by assuming that "abc"[0] is constant expression. It is not. Weird omission in the language. It would be possibe had "abc"[0] been constand expression.
This is only possible with C++0x. No chance with C++03.
EDIT: Constexpr function for C++0x. The following works with GCC4.6, however the Standard is not explicit in allowing it, and a small wording tweak was and is being considered to make the spec allow it.
constexpr bool isequal(char const *one, char const *two) {
*one == *two && (!*one || isEqual(one + 1, two + 1));
}
static_assert(isequal("foo", "foo"), "this should never fail");
static_assert(!isequal("foo", "bar"), "this should never fail");
The compiler is required to track the reference to characters of the string literals already, throughout all the recursions. Just the final read from characters isn't explicitly allowed (if you squint, you can read it as being allowed, IMO). If your compiler doesn't want to accept the above simple version, you can make your macro declare arrays and then compare those
#define CONCAT1(A, B) A ## B
#define CONCAT(A, B) CONCAT1(A, B)
#define CHECK_EQUAL(A, B) \
constexpr char CONCAT(x1, __LINE__)[] = A, \
CONCAT(x2, __LINE__)[] = B; \
static_assert(isequal(CONCAT(x1, __LINE__), CONCAT(x2, __LINE__)), \
"'" A "' and '" B "' are not equal!")
That's definitely fine.
CHECK_EQUAL("foo", "foo"); /* will pass */
CHECK_EQUAL("foo", "bar"); /* will fail */
Note that CHECK_EQUAL can be used inside of functions. The FCD did make a change to allow constexpr functions to read from automatic arrays in their invocation substitution. See DR1197.
No. You can not. Not even with boost::mpl or the boost preprocessor library. Even if you were to stipulate that the compiler could coalesce all duplicate string references into the same pointer value at compile-time, the pointer value does not exist until link-time. What you want to implement happens at preprocessor time, and then is asserted at compile-time.