De-duplication of NSString & unichar constants - c++

I have two simple constants:
NSString and
unichar,
defined as follows:
static NSString * const string = #"\u2022";
static unichar const character = 0x2022;
I'd want to have the number 0x2022 defined in one place.
I tried a lot of combinations (# and ##, also CFSTR macro) with no success.
Can it be done?

(Using ideas from How to concatenate twice with the C preprocessor and expand a macro as in "arg ## _ ## MACRO"?):
#define STRINGIFY(_x_) #_x_
#define UNICHAR_FROM_HEXCODE1(_c_) 0x ## _c_
#define UNICHAR_FROM_HEXCODE(_c_) UNICHAR_FROM_HEXCODE1(_c_)
#define NSSTRING_FROM_HEXCODE1(_c_) #"" STRINGIFY(\u ## _c_)
#define NSSTRING_FROM_HEXCODE(_c_) NSSTRING_FROM_HEXCODE1(_c_)
#define MYCHARCODE 2022
static unichar const character = UNICHAR_FROM_HEXCODE(MYCHARCODE);
static NSString * const string = NSSTRING_FROM_HEXCODE(MYCHARCODE);
Preprocessed output:
static unichar const character = 0x2022;
static NSString * const string = #"" "\u2022";
(Note that #"" "\u2022" is equivalent to #"\u2022".)

Related

Adding "L" to a string literal works to make it wide string, but not to a variable

The macro #define STR16(x) L ## x works when applied to string literals:
STR16("Hello") // fine, this is translated to L"Hello"
but not to variables:
STR16(x) // fails, this is translated to Lx, and the variable Lx doesn't exist
In line 200 of this useful library, there is a bug:
Parameter* param = new RangeParameter( STR16(p->GetNameForHost()), ...
will be translated to
Parameter* param = new RangeParameter( Lp->GetNameForHost(), ...
which fails, because Lp is an undeclared identifier.
How to do the same than adding L to a string literal, to a string variable const char * ?

C/C++ macro expansion

I have the following code:
#define UNIT_BASIC_UNIT_DEF2 (name) UNIT_BASIC_ ## name
#define UNIT_UNIT_TYPE_DEF2 (basic_type, name) UNIT_ ## basic_type ## _ ## name
#define UNIT_BASIC_UNIT_CLASS_NAME2(name) CUnit ## name
#define UNIT_UNIT_TYPE_CLASS_NAME2(basic_type, name) CUnit ## basic_type ## _ ## name
#define UNIT_BASIC_UNIT_DEF (name) UNIT_BASIC_UNIT_DEF2(name)
#define UNIT_UNIT_TYPE_DEF (basic_type, name) UNIT_UNIT_TYPE_DEF2 (basic_type, name)
#define UNIT_BASIC_UNIT_CLASS_NAME(name) UNIT_BASIC_UNIT_CLASS_NAME2(name)
#define UNIT_UNIT_TYPE_CLASS_NAME(basic_type, name) UNIT_UNIT_TYPE_CLASS_NAME2(basic_type, name)
#define UNIT_IMPLEMENT_UNIT_TYPE(basic_type, name) \
CUnitAbstract& UNIT_UNIT_TYPE_CLASS_NAME(basic_type, name)::dup(){\
UNIT_UNIT_TYPE_CLASS_NAME(basic_type, name) * n = new UNIT_UNIT_TYPE_CLASS_NAME(basic_type, name)(this->value);\
return *n;\
}\
CUnitAbstract& UNIT_UNIT_TYPE_CLASS_NAME(basic_type, name) ::operator+(CUnitAbstract& value){\
DYNAMIC_ASSERT(dynamic_cast< UNIT_BASIC_UNIT_CLASS_NAME(basic_type) *>(&value) != NULL);\
CUnitAbstract * tmp = &this->dup();\
*tmp = this->value + conversionTable[UNIT_BASIC_UNIT_DEF(basic_type)][UNIT_UNIT_TYPE_DEF(basic_type, name)] * value.getInBasicUnit();return *tmp;\
}
When I'm calling the macro with
UNIT_IMPLEMENT_UNIT_TYPE(DISTANCE, METER)
I get compilation errors:
error: 'basic_type' was not declared in this scope
error: 'name' was not declared in this scope
error: expected ']' before 'UNIT_basic_type_name'
error: expected ';' before 'UNIT_basic_type_name'
meaning that the macro wasn't expanded as I wanted it to in the last line inside the brackets.
What did I do wrong?
#define UNIT_BASIC_UNIT_DEF2 (name) UNIT_BASIC_ ## name
#define UNIT_UNIT_TYPE_DEF2 (basic_type, name) UNIT_ ## basic_type ## _ ## name
...
#define UNIT_BASIC_UNIT_DEF (name) UNIT_BASIC_UNIT_DEF2(name)
#define UNIT_UNIT_TYPE_DEF (basic_type, name) UNIT_UNIT_TYPE_DEF2 (basic_type, name)
Remove the spaces between the macro name and the argument list. These should be:
#define UNIT_BASIC_UNIT_DEF2(name) ...
// ^^^
// no space here!
When there's a space like this:
#define FOO (params) replacement
that defines an object-like macro, where the symbol gets directly replaced by the replacement list, with no parameter substitution. So an invocation like this:
FOO(bar)
gets expanded to this:
(params) replacement
By removing the space, you get a function-like macro as intended:
#define FOO(params) replacement
and FOO(bar) gets correctly expanded to replacement.

Concatenating #define in C++

I have something like:
#define BASE_FOLDER = "Resources"
#define PREFERENCE_FILE_NAME = "AppPreferences.txt"
#define SPLASH_FILE_NAME = "Splash.png"
#define PREFERENCE_PATH = ".\\" + BASE_FOLDER + "\\" + PREFERENCE_FILE_NAME
#define SPLASH_PATH = ".\\" + BASE_FOLDER + "\\" + SPLASH_FILE_NAME
and the compiler is throwing errors where PREFERENCE_PATH is used.
expecting primary expression before = token.
These all worked when I was doing
#define PREFERENCE_PATH = ".\\Resources\\AppPreferences.txt"
#define SPLASH_PATH = ".\\Resources\\Splash.png"
What am I doing wrong?
Get rid of the equal signs. Preprocessor definitions don't use equal signs.
Then get rid of the pluses. String literals are concatenated when you put them side by side without a plus in between. Emphasis on literals because this is a compile-time feature that only works with double-quoted literals, as in "foo" "bar" → "foobar". It doesn't work with variables.
#define BASE_FOLDER "Resources"
#define PREFERENCE_FILE_NAME "AppPreferences.txt"
#define SPLASH_FILE_NAME "Splash.png"
#define PREFERENCE_PATH ".\\" BASE_FOLDER "\\" PREFERENCE_FILE_NAME
#define SPLASH_PATH ".\\" BASE_FOLDER "\\" SPLASH_FILE_NAME
You can't concatenate strings (char* that is) in C++ like that...there is no + operator for them.

Macro String with variable

I don't know how to define a macro string with variable, like this:
#define str(x) "file x.txt", that mean I desire that str(1) refers to "file 1.txt".
However, in the case, str(1) or any number refers to "file x.txt", because x is an character.
Is there any way to solve this?
Concatenate the strings:
#define STR(x) "file " #x ".txt"
This makes use of a lexical feature of the two languages: adjacent string literals are concatenated; see both C++11 2.2/6 and C11 5.1.1.2/6:
Adjacent string literal tokens are concatenated.
#define str(x) ("file " #x ".txt")
using the stringification operator #

Is there a clean continuation line in C++ similar to C# #"Text" or Python """Text"""?

For example, for copy/paste purposes, it is very convenient to write :
C#
#"
SELECT * FROM ......
WHERE X = (SELECT Y FROM .....)
AND M IN ('1','2','3')
";
or
Python:
"""
SELECT * FROM ......
WHERE X = (SELECT Y FROM .....)
AND M IN ('1','2','3')
"""
than:
C++
"SELECT * FROM ...... \
WHERE X = (SELECT Y FROM .....) \
AND M IN ('1','2','3')"
Is there any way to avoid the \ style in C++ and approach to C# or python style?
Thanks.
C++ (as well as C) automatically concatenates adjacent string literals. There's no need for \ with string literals. E.g. this
const char *p = "Hello" "World"
"!";
is equivalent to
const char *p = "HelloWorld!";
In your case you can simply do
"SELECT * FROM ...... "
"WHERE X = (SELECT Y FROM .....) "
" AND M IN ('1','2','3')"
and the result will be equivalent to your original version with \, i.e. one continuous string literal will be produced.
This does not insert linebreaks or any other additional whitespace between the concatenated segments though. You have to remember to do it yourself, if you need something like that.
I think C++11 allows newlines in raw string literals, e.g.:
const char *query = R"(SELECT * FROM ......
WHERE X = (SELECT Y FROM .....)
AND M IN ('1','2','3'))";
Each newline in the source should result in a newline in the execution string-literal. Raw string literals generally take the form of R"( ... )". For GCC this requires at least version 4.5, and for clang++, it requires version 3.0. Alternatively, you can use a custom delimiter to make it easier to disambiguate the end of the string:
const char *query = R"XXXX(SELECT * FROM ......
WHERE X = (SELECT Y FROM .....)
AND M IN ('1','2','3'))XXXX";