Skip to content

Instantly share code, notes, and snippets.

@charlesnicholson
Last active December 3, 2021 20:08
Show Gist options
  • Save charlesnicholson/5f066d9f0ea2f7b484ac to your computer and use it in GitHub Desktop.
Save charlesnicholson/5f066d9f0ea2f7b484ac to your computer and use it in GitHub Desktop.
compile-time string concatenation
#include <cstdio>
namespace detail {
template<unsigned count, template<unsigned...> class meta_functor, unsigned... indices>
struct apply_range {
typedef typename apply_range<count - 1, meta_functor, count - 1, indices...>::result result;
};
template<template<unsigned...> class meta_functor, unsigned... indices>
struct apply_range<0, meta_functor, indices...> {
typedef typename meta_functor< indices... >::result result;
};
template<char... str> struct string {
static constexpr const char c_str[sizeof...(str) + 1] = { str..., '\0' };
};
template<char... str> constexpr const char string<str...>::c_str[sizeof...(str) + 1];
template<typename lambda_result> struct string_builder {
template<unsigned... indices> struct apply {
typedef string<lambda_result{}.chars[indices]...> result;
};
};
template< char... lhs, char... rhs >
string< lhs..., rhs... > operator +(string< lhs... >, string< rhs... >) { return {}; }
}
#define MAKE_STRING(string_literal) \
[]{ \
struct constexpr_string_type { const char *chars = string_literal; }; \
return detail::apply_range<sizeof(string_literal) - 1, detail::string_builder< constexpr_string_type >::apply>::result{}; \
}()
int main() {
auto hello = MAKE_STRING("hello");
auto world = MAKE_STRING(" world");
auto test = MAKE_STRING(" test");
std::printf("compile concat: %s\n", (hello + world + test).c_str);
}
@charlesnicholson
Copy link
Author

this is really just a cleaned-up version of http://stackoverflow.com/questions/15858141/conveniently-declaring-compile-time-strings-in-c that i'm reformatting and renaming to try and make sense of things.

@charlesnicholson
Copy link
Author

Cleaned up generated assembly with debug instructions + markers removed. Compiled with:

clang++ -std=gnu++11 -O3 --save-temps -fno-exceptions -fno-rtti -Wall -Wextra main.cpp
    .section    __TEXT,__text,regular,pure_instructions
    .globl  _main
    .align  4, 0x90
_main:                                  ## @main
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    leaq    L_.str(%rip), %rdi
    movq    __ZN6detail6stringIJLc104ELc101ELc108ELc108ELc111ELc32ELc119ELc111ELc114ELc108ELc100ELc32ELc116ELc101ELc115ELc116EEE5c_strE@GOTPCREL(%rip), %rsi
    xorl    %eax, %eax
    callq   _printf
    xorl    %eax, %eax
    popq    %rbp
    ret
    .cfi_endproc

    .section    __TEXT,__cstring,cstring_literals
L_.str:                                 ## @.str
    .asciz  "compile concat: %s\n"

    .section    __TEXT,__const_coal,coalesced
    .globl  __ZN6detail6stringIJLc104ELc101ELc108ELc108ELc111ELc32ELc119ELc111ELc114ELc108ELc100ELc32ELc116ELc101ELc115ELc116EEE5c_strE ## @_ZN6detail6stringIJLc104ELc101ELc108ELc108ELc111ELc32ELc119ELc111ELc114ELc108ELc100ELc32ELc116ELc101ELc115ELc116EEE5c_strE
    .weak_definition    __ZN6detail6stringIJLc104ELc101ELc108ELc108ELc111ELc32ELc119ELc111ELc114ELc108ELc100ELc32ELc116ELc101ELc115ELc116EEE5c_strE
    .align  4
__ZN6detail6stringIJLc104ELc101ELc108ELc108ELc111ELc32ELc119ELc111ELc114ELc108ELc100ELc32ELc116ELc101ELc115ELc116EEE5c_strE:
    .asciz  "hello world test"
.subsections_via_symbols

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment