One of the issues I have had in porting some stuff from Solaris to Linux is that the Solaris compiler expands the macro __FILE__ during preprocessing to the file name (e.g. MyFile.cpp) whereas gcc on Linux expandeds out to the full path (e.g. /home/user/MyFile.cpp). This can be reasonably easily resolved using basename() but....if you're using it a lot, then all those calls to basename() have got to add up, right?
Here's the question. Is there a way using templates and static metaprogramming, to run basename() or similar at compile time? Since __FILE__ is constant and known at compile time this might make it easier. What do you think? Can it be done?
In projects using CMake to drive the build process, you can use a macro like this to implement a portable version that works on any compiler or platform. Though personally I pity the fool who must use something other than gcc... :)
# Helper function to add preprocesor definition of FILE_BASENAME
# to pass the filename without directory path for debugging use.
#
# Note that in header files this is not consistent with
# __FILE__ and __LINE__ since FILE_BASENAME will be the
# compilation unit source file name (.c/.cpp).
#
# Example:
#
# define_file_basename_for_sources(my_target)
#
# Will add -DFILE_BASENAME="filename" for each source file depended on
# by my_target, where filename is the name of the file.
#
function(define_file_basename_for_sources targetname)
get_target_property(source_files "${targetname}" SOURCES)
foreach(sourcefile ${source_files})
# Add the FILE_BASENAME=filename compile definition to the list.
get_filename_component(basename "${sourcefile}" NAME)
# Set the updated compile definitions on the source file.
set_property(
SOURCE "${sourcefile}" APPEND
PROPERTY COMPILE_DEFINITIONS "FILE_BASENAME=\"${basename}\"")
endforeach()
endfunction()
Then to use the macro, just call it with the name of the CMake target:
define_file_basename_for_sources(myapplication)
Using C++11, you have a couple of options. Let's first define:
constexpr int32_t basename_index (const char * const path, const int32_t index = 0, const int32_t slash_index = -1)
{
return path [index]
? ( path [index] == '/'
? basename_index (path, index + 1, index)
: basename_index (path, index + 1, slash_index)
)
: (slash_index + 1)
;
}
If your compiler supports statement expressions, and you want to be sure that the basename computation is being done at compile-time, you can do this:
// stmt-expr version
#define STRINGIZE_DETAIL(x) #x
#define STRINGIZE(x) STRINGIZE_DETAIL(x)
#define __FILELINE__ ({ static const int32_t basename_idx = basename_index(__FILE__);\
static_assert (basename_idx >= 0, "compile-time basename"); \
__FILE__ ":" STRINGIZE(__LINE__) ": " + basename_idx;})
If your compiler doesn't support statement expressions, you can use this version:
// non stmt-expr version
#define __FILELINE__ (__FILE__ ":" STRINGIZE(__LINE__) ": " + basename_index(__FILE__))
With this non stmt-expr version, gcc 4.7 and 4.8 call basename_index at run-time, so you're better off using the stmt-expr version with gcc. ICC 14 produces optimal code for both versions. ICC13 can't compile the stmt-expr version, and produces suboptimal code for the non stmt-expr version.
Just for completeness, here's the code all in one place:
#include <iostream>
#include <stdint.h>
constexpr int32_t basename_index (const char * const path, const int32_t index = 0, const int32_t slash_index = -1)
{
return path [index]
? ( path [index] == '/'
? basename_index (path, index + 1, index)
: basename_index (path, index + 1, slash_index)
)
: (slash_index + 1)
;
}
#define STRINGIZE_DETAIL(x) #x
#define STRINGIZE(x) STRINGIZE_DETAIL(x)
#define __FILELINE__ ({ static const int32_t basename_idx = basename_index(__FILE__); \
static_assert (basename_idx >= 0, "compile-time basename"); \
__FILE__ ":" STRINGIZE(__LINE__) ": " + basename_idx;})
int main() {
std::cout << __FILELINE__ << "It works" << std::endl;
}
There is currently no way of doing full string processing at compile time (the maximum we can work with in templates are the weird four-character-literals).
Why not simply save the processed name statically, e.g.:
namespace
{
const std::string& thisFile()
{
static const std::string s(prepocessFileName(__FILE__));
return s;
}
}
This way you are only doing the work once per file. Of course you can also wrap this into a macro etc.
you might want to try the __BASE_FILE__ macro. This page describes a lot of macros which gcc supports.
Another C++11 constexpr method is as follows:
constexpr const char * const strend(const char * const str) {
return *str ? strend(str + 1) : str;
}
constexpr const char * const fromlastslash(const char * const start, const char * const end) {
return (end >= start && *end != '/' && *end != '\\') ? fromlastslash(start, end - 1) : (end + 1);
}
constexpr const char * const pathlast(const char * const path) {
return fromlastslash(path, strend(path));
}
The usage is pretty simple also:
std::cout << pathlast(__FILE__) << "\n";
The constexpr will be performed at compile-time if possible, otherwise it will fallback to run-time execution of the statements.
The algorithm is a little different in that it finds the end of the string and then works backwards to find the last slash. It is probably slower than the other answer but since it is intended to be executed at compile-time it shouldn't be an issue.
I like #Chetan Reddy's answer, which suggests using static_assert() in a statement expression to force a compile time call to function finding the last slash, thus avoiding runtime overhead.
However, statement expressions are a non-standard extension and are not universally supported. For instance, I was unable to compile the code from that answer under Visual Studio 2017 (MSVC++ 14.1, I believe).
Instead, why not use a template with integer parameter, such as:
template <int Value>
struct require_at_compile_time
{
static constexpr const int value = Value;
};
Having defined such a template, we can use it with basename_index() function from #Chetan Reddy's answer:
require_at_compile_time<basename_index(__FILE__)>::value
This ensures that basename_index(__FILE__) will in fact be called at compile time, since that's when the template argument must be known.
With this, the complete code for, let's call it JUST_FILENAME, macro, evaluating to just the filename component of __FILE__ would look like this:
constexpr int32_t basename_index (
const char * const path, const int32_t index = 0, const int32_t slash_index = -1
)
{
return path [index]
? ((path[index] == '/' || path[index] == '\\') // (see below)
? basename_index (path, index + 1, index)
: basename_index (path, index + 1, slash_index)
)
: (slash_index + 1)
;
}
template <int32_t Value>
struct require_at_compile_time
{
static constexpr const int32_t value = Value;
};
#define JUST_FILENAME (__FILE__ + require_at_compile_time<basename_index(__FILE__)>::value)
I've stolen basename_index() almost verbatim from the previously mentioned answer, except I added a check for Windows-specific backslash separator.
Another possible approach when using CMake is to add a custom preprocessor definition that directly uses make's automatic variables (at the cost of some arguably ugly escaping):
add_definitions(-D__FILENAME__=\\"$\(<F\)\\")
Or, if you're using CMake >= 2.6.0:
cmake_policy(PUSH)
cmake_policy(SET CMP0005 OLD) # Temporarily disable new-style escaping.
add_definitions(-D__FILENAME__=\\"$\(<F\)\\")
cmake_policy(POP)
(Otherwise CMake will over-escape things.)
Here, we take advantage of the fact make substitutes $(<F) with the source file name without leading components and this should show up as -D__FILENAME__=\"MyFile.cpp\" in the executed compiler command.
(While make's documentation recommends using $(notdir path $<) instead, not having whitespace in the added definition seems to please CMake better.)
You can then use __FILENAME__ in your source code like you'd use __FILE__. For compatibility purposes you may want to add a safe fallback:
#ifndef __FILENAME__
#define __FILENAME__ __FILE__
#endif
For Objective-C the following macro provides a CString which can replace the __FILE__ macro, but omitting the initial path components.
#define __BASENAME__ [[[NSString stringWithCString:__FILE__ \
encoding:NSUTF8StringEncoding] \
lastPathComponent] \
cStringUsingEncoding:NSUTF8StringEncoding]
That is to say it converts: /path/to/source/sourcefile.m into: sourcefile.m
It works by taking the ouptput of the __FILE__ macro (which is a C-formatted, null terminated string), converting it to an Objective-C string object, then stripping out the initial path components and finally converting it back into a C formatted string.
This is useful to get logging format which is more readable, replacing, (for example) a logging macro like this:
#define MyLog(fmt, ...) MyLog((#"E %s [Line %d] " fmt), \
__FILE__, __LINE__, ##__VA_ARGS__)
with:
#define __BASENAME__ [[[NSString stringWithCString:__FILE__ \
encoding:NSUTF8StringEncoding] \
lastPathComponent] \
cStringUsingEncoding:NSUTF8StringEncoding]
#define MyLog(fmt, ...) MyLog((#"E %s [Line %d] " fmt), \
__BASENAME__, __LINE__, ##__VA_ARGS__)
It does contain some runtime elements, and in that sense does not fully comply with the question, but it is probably appropriate for most circumstances.
I've compressed the constexpr version down to one recursive function that finds the last slash and returns a pointer to the character after the slash. Compile time fun.
constexpr const char* const fileFromPath(const char* const str, const char* const lastslash = nullptr) {
return *str ? fileFromPath(str + 1, ((*str == '/' || *str == '\\') ? str + 1 : (nullptr==lastslash?str:lastslash)) : (nullptr==lastslash?str:lastslash);
}
Related
I have
#define ARG(TEXT , REPLACEMENT) replace(#TEXT, REPLACEMENT)
so
QString str= QString("%ONE, %TWO").ARG(%ONE, "1").ARG(%TWO, "2");
becomes
str= QString("%ONE, %TWO").replace("%ONE", "1").replace("%TWO", "2");
//str = "1, 2"
The problem is that VS2019, when formatting the code (Edit.FormatSelection) interprets that % sign as an operator and adds a whitespace
QString str= QString("%ONE, %TWO").ARG(% ONE, "1").ARG(% TWO, "2");
(I think it's a bug in VS). The code compiles without warnings.
As I am dealing with some ancient code that has this "feature" spread, I'm worried to auto-format text containing this and break functionality.
Is there a way at compile time to detect such arguments to a macro having space(s)?
Is there a way at compile time to detect such arguments to a macro having space(s)?
Here's what I would do:
#define ARG(TEXT, REPLACEMENT) \
replace([]{ \
static constexpr char x[] = #TEXT; \
static_assert(x[0] == '%' && x[1] != ' '); \
return x; \
}(), REPLACEMENT)
Apparently some time in the next decade C++ will provide a better solution, and indeed there might be a much less clunky solution than the one I provide below, but it's maybe a place to start.
This version uses the Boost Preprocessor library to do a repetition which would have been straight-forward to write with a template if C++ allowed string literals as template arguments, a feature which has not yet gotten into the standard for motivations I can only guess at. So it doesn't actually test whether the argument has no spaces; rather it tests that there are no spaces in the first 64 characters (where 64 is an almost entirely arbitrary number which can be changed as your needs dictate). I used the Boost Preprocessor library; you could do this with your own special purpose macros if for some reason you don't want to use Boost.
#include <boost/preprocessor/repetition/repeat.hpp>
#define NO_SPACE_AT_N(z, N, s) && (N >= sizeof(s) || s[N] != ' ')
#define NO_SPACE(s) true BOOST_PP_REPEAT(64, NO_SPACE_AT_N, s)
// Arbitrary constant, change as needed---^
// Produce a compile time error if there's a space.
template<bool ok> struct NoSpace {
const char* operator()(const char* s) {
static_assert(ok, "Unexpected space");
return s;
}
};
#define ARG(TEXT, REPL) replace(NoSpace<NO_SPACE(#TEXT)>()(#TEXT), REPL)
(Test on gcc.godbolt.)
If the question is to produce a compilation error when the first argument of ARG contains a space, I managed to get this to work:
#include <cstdlib>
template<size_t N>
constexpr int string_validate( const char (&s)[N] )
{
for (int i = 0; i < N; ++i)
if ( s[i] == ' ' )
return 0;
return 1;
}
template<int N> void assert_const() { static_assert(N, "string validation failed"); }
int replace(char const *, char const *) { return 0; } // dummy for example
#define ARG(TEXT , REPLACEMENT) replace((assert_const<string_validate(#TEXT)>(), #TEXT), REPLACEMENT)
int main()
{
auto b = ARG(%TWO, "2");
auto a = ARG(% ONE, "1"); // causes assertion failure
}
Undoubtedly there is a shorter way. Prior to C++20 you can't use a string literal in a template parameter, hence the constexpr function to produce an integer from the string literal and then we can check the integer at compile-time by using it as a template parameter.
It's unlikely.
Visual Studio works on source code, without running the preprocessor first and without performing what would be quite a difficult computation to work out whether the preprocessor would fundamentally alter the line it's formatting.
Besides, people don't really use macros in this way any more, or shouldn't (we have cheap functions!).
So this isn't really what the formatting feature expects.
If you can modify the code, make the user write .ARG("%ONE", "1"), then not only does the problem go away but also the would be more consistent.
Otherwise, you'll have to stick with formatting the code by hand.
Under Windows, I have an environment variable that contains a Windows-style path. I'd like to build that path into my program and print it out. So if my path is c:\top, I pass it into the compiler using -DTOP=$(TOP). Note I cannot convert it to c:\\top before I pass it into the compiler.
Right now, I have the equivalent of:
#define TOP=c:\top
I want the equivalent of:
char path[]="c:\\top";
I can't just use the stringafication operator:
#define WRAP1(X) #X
#define WRAP(X) WRAP1(X)
char path[] = WRAP(TOP);
That just results in the string "c:\top" which the compiler views as an escape sequence (i.e. \t).
I think a possible solution would be to construct a string literal, but other solutions will be also be fine. Is there a way to use macros to construct a string literal that would yield:
char path[] = R"foo(c:\top)foo";
So far, all my attempts have failed for reasons involving the variations of the " or ( ) or the \ .
Thanks.
You can convert your defined path to a string by prefixing it with the stringizing operator #. However, this only works in macros. You actually need a double-macro to make it work properly, otherwise it just prints TOP. Also placing the pathname in quotes is important - oh the example has the path stored under the env PathDirName
Defining the path for the compiler -
/DTOP="\"$(PathDirName)\\""
Using within the code
#define STRINGIZE2(x) #x
#define STRINGIZE(x) STRINGIZE2(x)
char path[] = STRINGIZE(TOP);
This has worked for me. You nearly had it working, so hope this helps.
[EDIT] I can see the problem now - within C:\top - its taking the 'backslash t' as a control code - '\t'. This appoarch is becoming a little bit of a nightmare to work out - as you really need to create the file name with two slashes or use forward slashes. I do feel I have confused issues here by answering before reviewing fully what has happened.
I have tried several methods - but not being able to change the passed in define - I can only suggest using a regex library or manual scanning the string - replacing the control charactors with the correct '\' letter.
I've knocked up an example showing this just with the '\t' in your example - It's not nice code, it's written to explain what is being done, hopefully it gives an visual example and it does (in a not so nice way) sort out the ONE issue you are having with 'C:\top' .. as I have said - if using this cough, method, you will need to handle all control codes. :-)
char stringName[256];
char* pRefStr = STRING(TOP);
char* pDestStr = stringName;
int nStrLen = strlen( pRefStr );
for( int nIndex = 0; nIndex < nStrLen; nIndex++ )
{
if ( *pRefStr == '\t' )
{
*pDestStr++ = '\\';
*pDestStr++ = 't';
pRefStr++;
}
else
{
*pDestStr++ = *pRefStr++;
}
}
*pDestStr = '\0';
Once again - sorry for any confusion - I've left my answer here as reference for you - and hopefully someone will come up with a way of handling the define-string (with the control charactors).
thanks, Neil
The rather bizarre syntax you're looking for performs on-the-fly substring replacement in variable expansion, as well as some quote mark escaping to make the definition a string. I found the substring replacement information here.
set DIR=C:\WINDOWS gets the env var set, and then we have a test prog:
#include <stdio.h>
#define STR(x) #x
#define STRING(x) STR(x)
int main( int argc, char* argv[] )
{
printf( "DIR: %s\n", STRING(DIR) );
return 0;
}
As you cannot quote in the shell, you can stringize here, but you must still do the variable substring replacement.
Pass the env var in through cmd.exe:
gcc -Wall -DDIR=%DIR:\=\\% main.c
See the link above for more information, or google substring replacement. I can't find a link to any Microsoft info on the function (what a surprise!)
There is a lot of wide string numeric constants defined in one include file in one SDK, which I cannot modify, but which gets often updated and changed. So I cannot declare the numeric define with the numbers because It is completely different each few days and I don't want ('am not allowed) to apply any scripting for updating
If it would be the other way round and the constant would be defined as a number, I can simply make the string by # preprocessor operator.
I don't won't to use atoi and I don't want to make any variables, I just need the constants in numeric form best by preprocessor.
I know that there is no reverse stringizing operator, but isn't there any way how to convert string to token (number) by preprocessor?
There is no way to "unstringify" a string in the preprocessor. However, you can get, at least, constant expressions out of the string literals using user-defined literals. Below is an example initializing an enum value with the value taken from a string literal to demonstrate that the decoding happens at compile time, although not during preprocessing:
#include <iostream>
constexpr int make_value(int base, wchar_t const* val, std::size_t n)
{
return n? make_value(base * 10 + val[0] - L'0', val + 1, n -1): base;
}
constexpr int operator"" _decode(wchar_t const* val, std::size_t n)
{
return make_value(0, val, n);
}
#define VALUE L"123"
#define CONCAT(v,s) v ## s
#define DECODE(d) CONCAT(d,_decode)
int main()
{
enum { value = DECODE(VALUE) };
std::cout << "value=" << value << "\n";
}
Let's say I have these two overloads:
void Log(const wchar_t* message)
{
// Do something
}
void Log(const std::wstring& message)
{
// Do something
}
Can I then in the first function add some compile-time verifiction that the passed argument is a string literal?
EDIT: A clarification on why this would be good in my case; my current high-frequency logging uses only string literals and can hence be optimized a lot when there are non-heap allocation guarantees. The second overload doesn't exist today, but I might want to add it, but then I want to keep the first one for extreme scenarios. :)
So this grew out of Keith Thompson's answer... As far as I know, you can't restrict string literals to only normal functions, but you can do it to macro functions (through a trick).
#include <iostream>
#define LOG(arg) Log(L"" arg)
void Log(const wchar_t *message) {
std::wcout << "Log: " << message << "\n";
}
int main() {
const wchar_t *s = L"Not this message";
LOG(L"hello world"); // works
LOG(s); // terrible looking compiler error
}
Basically, a compiler will convert "abc" "def" to look exactly like "abcdef". And likewise, it will convert "" "abc" to "abc". You can use this to your benefit in this case.
I also saw this comment on the C++ Lounge, and that gave me another idea of how to do this, which gives a cleaner error message:
#define LOG(arg) do { static_assert(true, arg); Log(arg); } while (false)
Here, we use the fact that static_assert requires a string literal as it's second argument. The error that we get if we pass a variable instead is quite nice as well:
foo.cc:12:9: error: expected string literal
LOG(s);
^
foo.cc:3:43: note: expanded from macro 'LOG'
#define LOG(arg) do { static_assert(true, arg); Log(arg); } while (false)
I believe the answer to your question is no -- but here's a way to do something similar.
Define a macro, and use the # "stringification" operator to guarantee that only a string literal will be passed to the function (unless somebody bypasses the macro and calls the function directly). For example:
#include <iostream>
#define LOG(arg) Log(#arg)
void Log(const char *message) {
std::cout << "Log: " << message << "\n";
}
int main() {
const char *s = "Not this message";
LOG("hello world");
LOG(hello world);
LOG(s);
}
The output is:
Log: "hello world"
Log: hello world
Log: s
The attempt to pass s to LOG() did not trigger a compile-time diagnostic, but it didn't pass that pointer to the Log function.
There are at least two disadvantages to this approach.
One is that it's easily bypassed; you may be able to avoid that by searching the source code for references to the actual function name.
The other is that stringifying a string literal doesn't just give you the same string literal; the stringified version of "hello, world" is "\"hello, world\"". I suppose your Log function could strip out any " characters in the passed string. You may also want to handle backslash escapes; for example, "\n" (a 1-character string containing a newline) is stringified as "\\n" (a 2-character string containing a backslash and the letter n).
But I think a better approach is not to rely on the compiler to diagnose calls with arguments other than string literals. Just use some other tool to scan the source code for calls to your Log function and report any calls where the first argument isn't a string literal. If you can enforce a particular layout for the calls (for example, the tokens Log, (, and a string literal on the same line), that shouldn't be too difficult.
You can't detect string literals directly but you can detect if the argument is an array of characters which is pretty close. However, you can't do it from the inside, you need to do it from the outside:
template <std::size_t Size>
void Log(wchar_t const (&message)[Size]) {
// the message is probably a string literal
Log(static_cast<wchar_t const*>(message);
}
The above function will take care of wide string literals and arrays of wide characters:
Log(L"literal as demanded");
wchar_t non_literal[] = { "this is not a literal" };
Log(non_literal); // will still call the array version
Note that the information about the string being a literal isn't as useful as one might hope for. I frequently think that the information could be used to avoid computing the string length but, unfortunately, string literals can still embed null characters which messes up static deduction of the string length.
If you define Log as a macro instead, and call separate methods for literal versus std::wstring handling, some variation of the following should work:
#define Log(x) ((0[#x] == 'L' && 1[#x] == '"') ? LogLiteral(x) : LogString(x))
void
LogLiteral (const wchar_t *s) {
//...do something
}
void
LogString (const std::wstring& s) {
//...do something
}
The trick is that you need opposing definitions of LogLiteral() so that the compilation will pass, but it should never be called.
inline void LogLiteral (const std::wstring &s) {
throw std::invalid_argument(__func__);
}
This code gives you the behavior of an overloaded Log() method, in that you can pass either a string literal or a non-string literal to the Log() macro, and it will end up calling either LogLiteral() or LogString(). This gives compile time verification in that the compiler will not pass anything except what the code recognizes as a string literal to the call to LogLiteral(). At sufficient optimizations, the conditional branch can be removed, since every instance of the check is static (on GCC, it is removed).
Here's a quick example I just whipped up using the printf hack I suggested in the comments above:
#include <cstdio>
#define LOG_MACRO(x) do { if (0) printf(x); Log(x); } while (0)
void Log(const char *message)
{
// do something
}
void function(void)
{
const char *s = "foo";
LOG_MACRO(s);
LOG_MACRO("bar");
}
Output from compiling this one with Clang appears to be exactly what you're looking for:
$ clang++ -c -o example.o example.cpp
example.cpp:13:15: warning: format string is not a string literal
(potentially insecure) [-Wformat-security]
LOG_MACRO(s);
^
example.cpp:3:41: note: expanded from macro 'LOG_MACRO'
#define LOG_MACRO(x) do { if (0) printf(x); Log(x); } while (0)
^
1 warning generated.
I did have to switch to printf rather than wprintf, since the latter appears not to generate the warning - I guess that's probably a Clang bug, though.
GCC's output is similar:
$ g++ -c -o example.o example.cpp
example.cpp: In function ‘void function()’:
example.cpp:13: warning: format not a string literal and no format arguments
example.cpp:13: warning: format not a string literal and no format arguments
Edit: You can see the Clang bug here. I just added a comment about -Wformat-security.
I don't think you can enforce to pass only a string literal to a function, but literals are character arrays, what you can enforce:
#include <iostream>
template<typename T>
void log(T) = delete; //Disable everything
template <std::size_t Size>
void log(const wchar_t (&message)[Size]) //... but const wchar_t arrays
{
std::cout << "yay" << std::endl;
}
const wchar_t * get_str() { return L"meow"; }
int main() {
log(L"foo"); //OK
wchar_t arr[] = { 'b', 'a', 'r', '0' };
log(arr); //Meh..
// log(get_str()); //compile error
}
Downside is that if you have a runtime character array, it will work as well, but won't work for the usual runtime c-style strings.
But, if you can work with a slightly different syntax, then the answer is YES:
#include <cstddef>
#include <iostream>
void operator"" _log ( const wchar_t* str, size_t size ) {
std::cout << "yay" << std::endl;
}
int main() {
L"Message"_log;
}
Of course, both solution needs a C++11-compatible compiler (example tested with G++ 4.7.3).
Adding this alternative for future reference. It comes from the SO question Is it possible to overload a function that can tell a fixed array from a pointer?
#include <iostream>
#include <type_traits>
template<typename T>
std::enable_if_t<std::is_pointer<T>::value>
foo(T)
{
std::cout << "pointer\n";
}
template<typename T, unsigned sz>
void foo(T(&)[sz])
{
std::cout << "array\n";
}
int main()
{
char const* c = nullptr;
char d[] = "qwerty";
foo(c);
foo(d);
foo("hello");
}
The above snippet compiles and runs fine on http://webcompiler.cloudapp.net/
I need to replace
GET("any_name")
with
String str_any_name = getFunction("any_name");
The hard part is how to trim off the quote marks. Possible? Any ideas?
How about:
#define UNSAFE_GET(X) String str_##X = getFunction(#X);
Or, to safe guard against nested macro issues:
#define STRINGIFY2(x) #x
#define STRINGIFY(x) STRINGIFY2(x)
#define PASTE2(a, b) a##b
#define PASTE(a, b) PASTE2(a, b)
#define SAFE_GET(X) String PASTE(str_, X) = getFunction(STRINGIFY(X));
Usage:
SAFE_GET(foo)
And this is what is compiled:
String str_foo = getFunction("foo");
Key points:
Use ## to combine macro parameters into a single token (token => variable name, etc)
And # to stringify a macro parameter (very useful when doing "reflection" in C/C++)
Use a prefix for your macros, since they are all in the same "namespace" and you don't want collisions with any other code. (I chose MLV based on your user name)
The wrapper macros help if you nest macros, i.e. call MLV_GET from another macro with other merged/stringized parameters (as per the comment below, thanks!).
One approach is not to quote the name when you call the macro:
#include <stdio.h>
#define GET( name ) \
int int##name = getFunction( #name ); \
int getFunction( char * name ) {
printf( "name is %s\n", name );
return 42;
}
int main() {
GET( foobar );
}
In answer to your question, no, you can't "strip off" the quotes in C++. But as other answers demonstrate, you can "add them on." Since you will always be working with a string literal anyway (right?), you should be able to switch to the new method.