hlide
hlide

Reputation: 376

How to strip a string given as a const char[] through a constexpr function?

I want to define a constexpr function strip_string which allows:

  1. Trim the string (removal of contiguous whitespaces in the beginning and end of the string.
  2. Normalize contiguous whitespaces in the middle of the string to one space.
  3. Return a const char* of the final size as a constant so the binary will contain the reduced string and not the original string.
  4. The size of the resulted string should be the reduced one, not the size of the original string.

The purpose is to keep a readable string in the source and have the shortest string in the binary.

I'm using Visual Studio C++ 2017.

As an example:

I want that in my source (and only in my source, not in my binary!):

R"SQL("

CREATE TABLE IF NOT EXISTS "MyTable" (
    "ID"                    INTEGER NOT NULL,
    "Field1"                TEXT NOT NULL,
    "Field2"                TEXT,
    PRIMARY KEY("ID")
)

)SQL"

And only that in my binary (and no original string!):

CREATE TABLE IF NOT EXISTS "MyTable" ( "ID" INTEGER NOT NULL, "Field1" TEXT NOT NULL, "Field2" TEXT, PRIMARY KEY("ID"))

And here the last attempt of code which still shows using constexpr before each functions is not enough to turn them into real constants:

#include <cstddef>
#include <utility>
#include <iostream>

constexpr bool is_whitespace(char c) {
    return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v';
}

template<std::size_t N>
constexpr std::size_t calculate_final_length(const char (&input)[N]) {
    std::size_t start = 0;
    std::size_t end = N - 1;

    while (start < end && is_whitespace(input[start])) {
        ++start;
    }

    while (end > start && is_whitespace(input[end - 1])) {
        --end;
    }

    std::size_t trimmed_length = end - start;

    std::size_t final_length = 0;
    bool in_whitespace = false;

    for (std::size_t i = 0; i < trimmed_length; ++i) {
        char c = input[start + i];
        if (is_whitespace(c)) {
            if (!in_whitespace) {
                ++final_length;
                in_whitespace = true;
            }
        } else {
            ++final_length;
            in_whitespace = false;
        }
    }

    return final_length;
}

template<std::size_t N>
constexpr auto strip_string(const char (&input)[N]) {
    constexpr std::size_t final_length = calculate_final_length(input); // Fails to turn it into constant

    char result[final_length + 1] = {};
    std::size_t out_index = 0;
    bool in_whitespace = false;

    // Calculer les indices de début et de fin après suppression des blancs
    std::size_t start = 0;
    std::size_t end = N - 1;

    while (start < end && is_whitespace(input[start])) {
        ++start;
    }

    while (end > start && is_whitespace(input[end - 1])) {
        --end;
    }

    // Calculer la longueur après trim
    std::size_t trimmed_length = end - start;

    // Remplir le tableau résultant avec les caractères traités
    for (std::size_t i = 0; i < trimmed_length; ++i) {
        char c = input[start + i];
        if (is_whitespace(c)) {
            if (!in_whitespace) {
                result[out_index++] = ' ';
                in_whitespace = true;
            }
        } else {
            result[out_index++] = c;
            in_whitespace = false;
        }
    }

    result[out_index] = '\0';

    return result;
}

constexpr const char raw_string[] = ;
constexpr auto test = strip_string(
    R"(   This is     a  RAW string     test   )");


int main() {
    std::cout << test;
    std::cout << '\n';
    return 0;
}

As the code was never able to compile, I couldn't test it further.

Upvotes: -1

Views: 210

Answers (1)

Minxin Yu - MSFT
Minxin Yu - MSFT

Reputation: 4247

The error means: An expression declared as const or constexpr didn't evaluate to a constant at compile time.

Check the Compiler Error C2131 sammple:

struct test
{
    static const int array_size; // To fix, init array_size here.
    int size_array[array_size];  // C2131
};


const int test::array_size = 42;

Even the example link in the comments uses const N.

template<std::size_t N>
struct ct_string {
  char bytes[N];

char result[final_length + 1] = {};

using non-const variables does not meet the requirements.

Upvotes: -1

Related Questions