Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to concat two constexpr c-string?

655 views
Skip to first unread message

wij

unread,
Aug 26, 2023, 6:01:52 AM8/26/23
to
constexpr const char K1[]="abc";
constexpr const char K2[]="efg";
constexpr const char K3[]= ??? // "abcefg" expected

I'd like K3 to be "abcefg", how should I do?

Öö Tiib

unread,
Aug 26, 2023, 6:44:44 AM8/26/23
to
You can not make any functions that return char array (or whatever other
raw array) so there are no way. Raw arrays can't be passed by value in C++.
You can make std::array compile time as it can be passed.

Bonita Montero

unread,
Aug 26, 2023, 6:51:54 AM8/26/23
to
Not quite what you're looking for, but would you be happy with it?

#include <string_view>

constexpr char const *concatted = "abcdefg";
constexpr std::string_view
first( concatted, 3 ),
second( concatted + 3, 3 );

Bonita Montero

unread,
Aug 26, 2023, 7:15:49 AM8/26/23
to
Or more C++-ish:

constexpr std::string_view
concatted( "abcdefg" ),
first( concatted.data(), 3 ),
second( concatted.data() + 3, 3 );

wij

unread,
Aug 26, 2023, 9:17:47 AM8/26/23
to
I saw an example made for C++11, it looked strange... I don't have any idea:
(can I make the initialization of str3 successful?)

//-------------
// copy from https://juejin.cn/s/c%2B%2B%20concat%20constexpr%20string%20literals
//
#include <iostream>

constexpr const char* operator+(const char* lhs, const char* rhs) {
int size_lhs = 0, size_rhs = 0;
while (lhs[size_lhs] != '\0') ++size_lhs;
while (rhs[size_rhs] != '\0') ++size_rhs;

char* result = new char[size_lhs + size_rhs + 1];
int i = 0;
for (; i < size_lhs; ++i) result[i] = lhs[i];
for (int j = 0; j < size_rhs; ++j, ++i) result[i] = rhs[j];
result[i] = '\0';

return result;
}

int main() {
constexpr const char* str1 = "hello";
constexpr const char* str2 = " world";
constexpr const char* str3 = str1 + str2;
std::cout << str3 << std::endl;
return 0;
}

Bonita Montero

unread,
Aug 26, 2023, 9:22:18 AM8/26/23
to
Am 26.08.2023 um 15:17 schrieb wij:

> constexpr const char* operator+(const char* lhs, const char* rhs) {
> int size_lhs = 0, size_rhs = 0;
> while (lhs[size_lhs] != '\0') ++size_lhs;
> while (rhs[size_rhs] != '\0') ++size_rhs;
>
> char* result = new char[size_lhs + size_rhs + 1];
> int i = 0;
> for (; i < size_lhs; ++i) result[i] = lhs[i];
> for (int j = 0; j < size_rhs; ++j, ++i) result[i] = rhs[j];
> result[i] = '\0';
>
> return result;
> }

Why do you make a function calling new constexpr ?

wij

unread,
Aug 26, 2023, 9:33:11 AM8/26/23
to
1. I am not familiar with "constexpr"
2. The example is found on https://juejin.cn/s/c%2B%2B%20concat%20constexpr%20string%20literals , not made by me
3. I want the initialization effect like the str3 in the example

Bonita Montero

unread,
Aug 26, 2023, 9:57:15 AM8/26/23
to
Am 26.08.2023 um 15:33 schrieb wij:

> 1. I am not familiar with "constexpr"

There are three constexprs:
3. If you declare a function constexpr the compiler is requested
to compile-time evaluate the function if possible. If you have a
dynamic memory allocation that couldn't be compile-time evaluateable.
1. If you declare a variable constexpr the value assigned to it must
be compile-time evaluateable. Functions used to initialize the variable
must be constexpr and actually compile-time evaluatable.
2. If you have an if constexpr( expr ) expr must be compile-time
evaluateable. Functions called by expr must be also compie-time
evaluateable like with 2.

Alf P. Steinbach

unread,
Aug 26, 2023, 4:04:43 PM8/26/23
to
It depends on your requirements.

If you're free to use the preprocessor you can do simply


#define K1 "abc"
#define K2 "efg"
#define K3 K1 K2

constexpr auto& k1 = K1;
constexpr auto& k2 = K2;
constexpr auto& k3 = K3;


Easy peasy. :-)

- Alf

JiiPee

unread,
Sep 24, 2023, 4:48:31 AM9/24/23
to
On 26/08/2023 13:44, Öö Tiib wrote:
> You can make std::array compile time as it can be passed.

Am I right that in this kind of situationsa std::array is recommended
rather than C arrays?

JiiPee

unread,
Sep 24, 2023, 4:54:40 AM9/24/23
to
ye that view is surely good in this kind of things. I kinda "forgot" to
use it, should maybe use it more to become second nature.

JiiPee

unread,
Sep 24, 2023, 4:55:52 AM9/24/23
to
But isnt it that many recommend not to use define's?

David Brown

unread,
Sep 24, 2023, 5:56:12 AM9/24/23
to
When you have a fixed compile-time size for an array, I prefer
std::array, as it makes the array a "solid" object. (In C, I wrap the
array in a struct.) You can pass it by value, assign it, and so on.
You can use it like a container with some of the common container
methods and functions, for loops, and that kind of thing.

The key disadvantage of std::array is that since the size is part of the
type, you can't make a single non-template function that takes arrays of
different sizes as parameters. If that is not an issue for a particular
use-case, then std::array is often a nicer choice.

Alf P. Steinbach

unread,
Sep 24, 2023, 6:09:16 PM9/24/23
to
Yes. But with proper prefixes it's quite clean. Unfortunately the
standard language doesn't yet support pushing/popping macro definitions,
though individual implementations do as language extensions.

If you really want to avoid macros, /and/ want that compile time
concatenation really bad, consider something like


---
namespace my {
template< class Type > using in_ = const Type&;
template< class Type > using ref_ = Type&;

template< int n, class Item >
struct Wrapped_array_
{
using Raw = Item[n];
Raw items;

constexpr auto raw() const -> ref_<const Raw> { return items; }
};

template< int size_a, int size_b >
constexpr auto adjoined( in_<const char[size_a]> a, in_<const
char[size_b]> b )
-> Wrapped_array_<size_a + size_b - 1, char>
{
const int len_a = size_a - 1;
const int len_b = size_b - 1;
const int n = len_a + len_b + 1;

Wrapped_array_<n, char> result{};

for( int i = 0; i < len_a; ++i ) {
result.items[i] = a[i];
}
for( int i = 0; i < len_b; ++i ) {
result.items[i + len_a] = b[i];
}
result.items[n - 1] = '\0';
return result;
}
} // namespace my

#include <stdio.h>
auto main() -> int
{
constexpr auto& a = "abc";
constexpr auto& b = "def";
static constexpr auto c_wrapped = my::adjoined( a, b );
constexpr auto& c = c_wrapped.raw();

puts( c );
}
---

- Alf

0 new messages