Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to pull in a text resource into a raw string literal using the pre-processor?

I've just noticed that an answer I have given for this question actually doesn't work:

Regardless of using CMake or not, the following should work with the current standard:

std::string resource = R"(
#include "text.txt"
)";

I thought that the pre-processor would recognize the #include "text.txt" statement in first place and expand the text.

But that's obviously not the case, the result for

std::cout << resource << std::endl;

is

#include "text.txt"

I tried to use some macro to let the #include statement be expanded within, but it doesn't work either:

#include <string>
#include <iostream>

#define RESOURCE_DEFINIION(resource_var,resource_name) \
    const std::string resource_var = R"xxx( \
    #include resource_name \
    )xxx";

RESOURCE_DEFINIION(resource,"text.txt")

int main()
{
   std::cout << resource << std::endl; 

   return 0;
}

The output is

\                                                                                                                                                                                          
    #include resource_name \                                                                                                                                                                

Here's the demo to play with


Is there any trickery available to pull in the text.txt resource into a c++-11 raw-string literal, using the pre-processor or any other regular c++ language feature?


Disclaimer:

I well know what's wrong with the above samples and why these fail this way. It's a problem that the pre-processor ignores the stuff appearing within " pairs.

So is there a way to escape these to be seen by the pre-processor?

like image 624
πάντα ῥεῖ Avatar asked Jun 03 '16 20:06

πάντα ῥεῖ


People also ask

How do you make a string literal?

A "string literal" is a sequence of characters from the source character set enclosed in double quotation marks (" "). String literals are used to represent a sequence of characters which, taken together, form a null-terminated string. You must always prefix wide-string literals with the letter L.

What is a raw string literal?

Raw string literals are string literals that are designed to make it easier to include nested characters like quotation marks and backslashes that normally have meanings as delimiters and escape sequence starts. They're useful for, say, encoding text like HTML.

How does compiler process string literal?

The compiler scans the source code file, looks for, and stores all occurrences of string literals. It can use a mechanism such as a lookup table to do this. It then runs through the list and assigns the same address to all identical string literals.

What is a raw string literal in Python?

Python raw string is created by prefixing a string literal with 'r' or 'R'. Python raw string treats backslash (\) as a literal character. This is useful when we want to have a string that contains backslash and don't want it to be treated as an escape character.


1 Answers

It seems like not possible in standard C++

Problem 0: Only standard way of textual inclusion is #include directive.

Problem 1: String literal is a preprocessing token, which are recognised in phase 3, so when preprocessing directives are executed in phase 4, it is already determined that #include is a part of string literal and not a preprocessing directive.

preprocessing-token:
    header-name
    identifier
    pp-number
    character-literal
    user-defined-character-literal
    string-literal
    user-defined-string-literal
    preprocessing-op-or-punc
    each non-white-space character that cannot be one of the above

Problem 2: It is impossible to bring preprocessing directive in source and execute it by macro substitution:

16.3.4/3
The resulting completely macro-replaced preprocessing token sequence is not processed as a preprocessing directive even if it resembles one

So you cannot have working #include inside macro.

Problem 3: macro replacement list should be a valid preprocessing token:

control-line:
    # define identifier replacement-list new-line
replacement-list:
        pp-tokens opt
pp-tokens:
    preprocessing-token
    pp-tokens preprocessing-token

And string literal is a preprocessing token itself, you cannot build string literal from several macro.

like image 145
Revolver_Ocelot Avatar answered Nov 14 '22 23:11

Revolver_Ocelot