6

I'm trying to concatenate two compile time strings:

constexpr const char* getString1() { return "abababa"; };
constexpr const char* getString2() { return "lalalal"; };
constexpr const char* getString3() { return getString1() + getString2(); }; //wont compile

Is there a modern, simple way to do this in C++?

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
user5024425
  • 397
  • 3
  • 14

2 Answers2

2

This is a C++17 solution using std::apply.

NOTE: my usage of auto and requires pushes this into C++20.

This is actually possible by leveraging the fact that std::apply is constexpr meaning that you can access and tuple-type, including arrays, in terms of their underlying parameter pack:

#include <tuple>
#include <array>
#include <iostream>

//helper function:
//create array without the last element provided
//used to remove '\0' in concat
template <std::size_t N>
constexpr std::array<const char, N> trim(
    auto head, auto... chars
) requires (sizeof...(chars) == N) {
    if constexpr (sizeof...(chars) == 0) {
        return std::array<const char, 0>{}; //ignore last element
    } else {
        return std::apply([&head](auto... trim_chars){
            return std::array<const char, N>{head, trim_chars...}; //recurse
        }, trim<N - 1>(chars...));
    }
}

//concatonate 2 arrays by converting them into param backs using std::apply
//this works because std::apply is a constexpr function
template <std::size_t N, std::size_t M>
constexpr std::array<const char, N + M + 1> concat(
    const std::array<const char, N + 1>& n,
    const std::array<const char, M + 1>& m
) {
    std::array<const char, N> trim_n = std::apply([](auto... args){return trim<N>(args...);}, n);
    return std::apply([&](auto... n_chars){
        return std::apply([&](auto... m_chars){
            return std::array<const char, N + M + 1>{n_chars..., m_chars...};
        }, m);
    }, trim_n);
}

//example strings
constexpr std::array<const char, 4> x{"abc"};
constexpr std::array<const char, 4> y{"def"};
constexpr std::array<const char, 7> z = concat<3, 3>(x, y);

int main() {

    std::cout << &x[0] << " + " << &y[0] << " = " << &z[0];

}

This outputs:

abc + def = abcdef
1

Is there a modern, simple way to do this in C++?

The final answer is:

There is no way to do this actually at compile time using constexpr functions.

 return getString1() + getString2();

would try to add two pointers, which makes no sense for the compiler.

Any other attempts would require to inspect the actual character literals for concatenation (e.g. something like strcat()) which cannot be done at compile time.

The available alternatives are to use macros as pointed out in comments.


Maybe someone is able to do some black voodoo template magic, but I doubt it's worth the efforts anyway.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190