Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Concat two `const char` string literals

Is it possible to concat two string literals using a constexpr? Or put differently, can one eliminate macros in code like:

#define nl(str) str "\n"

int main()
{
  std::cout <<
      nl("usage: foo")
      nl("print a message")
      ;

  return 0;
}

Update: There is nothing wrong with using "\n", however I would like to know whether one can use constexpr to replace those type of macros.

like image 698
Micha Wiedenmann Avatar asked Nov 08 '12 15:11

Micha Wiedenmann


People also ask

How do you concatenate const char and string?

str() method to get std::string from it. std::string::c_str() function returns pointer to const char buffer (i.e. const char * ) of string contained within it, that is null-terminated. You can then use it as any other const char * variable. Better way would be to const char *C = (a + b).

How do you concatenate string literals?

Concatenate string literals in C/C++ A string literal is a sequence of characters, enclosed in double quotation marks (" ") , which is used to represent a null-terminated string in C/C++. If we try to concatenate two string literals using the + operator, it will fail.

Which is the correct way to concatenate 2 strings?

You concatenate strings by using the + operator. For string literals and string constants, concatenation occurs at compile time; no run-time concatenation occurs. For string variables, concatenation occurs only at run time.

Can you use += for string concatenation?

The + Operator The same + operator you use for adding two numbers can be used to concatenate two strings. You can also use += , where a += b is a shorthand for a = a + b .


3 Answers

A little bit of constexpr, sprinkled with some TMP and a topping of indices gives me this:

#include <array>

template<unsigned... Is> struct seq{};
template<unsigned N, unsigned... Is>
struct gen_seq : gen_seq<N-1, N-1, Is...>{};
template<unsigned... Is>
struct gen_seq<0, Is...> : seq<Is...>{};

template<unsigned N1, unsigned... I1, unsigned N2, unsigned... I2>
constexpr std::array<char const, N1+N2-1> concat(char const (&a1)[N1], char const (&a2)[N2], seq<I1...>, seq<I2...>){
  return {{ a1[I1]..., a2[I2]... }};
}

template<unsigned N1, unsigned N2>
constexpr std::array<char const, N1+N2-1> concat(char const (&a1)[N1], char const (&a2)[N2]){
  return concat(a1, a2, gen_seq<N1-1>{}, gen_seq<N2>{});
}

Live example.

I'd flesh this out some more, but I have to get going and wanted to drop it off before that. You should be able to work from that.

like image 53
Xeo Avatar answered Oct 07 '22 02:10

Xeo


  1. Yes, it is entirely possible to create compile-time constant strings, and manipulate them with constexpr functions and even operators. However,

  2. The compiler is not required to perform constant initialization of any object other than static- and thread-duration objects. In particular, temporary objects (which are not variables, and have something less than automatic storage duration) are not required to be constant initialized, and as far as I know no compiler does that for arrays. See 3.6.2/2-3, which define constant initialization, and 6.7.4 for some more wording with respect to block-level static duration variables. Neither of these apply to temporaries, whose lifetime is defined in 12.2/3 and following.

So you could achieve the desired compile-time concatenation with:

static const auto conc = <some clever constexpr thingy>;
std::cout << conc;

but you can't make it work with:

std::cout <<  <some clever constexpr thingy>;

Update:

But you can make it work with:

std::cout << *[]()-> const {
             static constexpr auto s = /* constexpr call */;
             return &s;}()
          << " some more text";

But the boilerplate punctuation is way too ugly to make it any more than an interesting little hack.


(Disclaimer: IANALL, although sometimes I like to play one on the internet. So there might be some dusty corners of the standard which contradicts the above.)

(Despite the disclaimer, and pushed by @DyP, I added some more language-lawyerly citations.)

like image 20
rici Avatar answered Oct 07 '22 02:10

rici


At first glance, C++11 user-defined string literals appear to be a much simpler approach. (If, for example, you're looking for a way to globally enable and disable newline injection at compile time)

like image 1
Ben Voigt Avatar answered Oct 07 '22 02:10

Ben Voigt