Home > Blockchain >  How to return compile-constant string literal with C constexpr function
How to return compile-constant string literal with C constexpr function

Time:10-28

I have a constexpr function and I'm trying to strip the file name from the __FILE__ macro, that is, remove everything but the path. I sketched up this basic function to do so, and I made it constexpr in hopes that the compiler can deduce the result and just place that calculated result as a string in the final binary. The function isn't perfect, just a simple mock-up.

constexpr const char* const get_filename()
{
    auto file{ __FILE__ };
    auto count{ sizeof(__FILE__) - 2 };

    while (file[count - 1] != '\\')
        --count;

    return &file[count];
}

int main()
{
    std::cout << get_filename() << std::endl;
    return 0;
}

The problem is that this is not being evaluated at compile time (build: MSVC x64 Release Maximum Speed optimization). I'm assuming this is because of returning a pointer to something inside a constant string in the binary, which is essentially what the function is doing. However, what I want the compiler to do is parse the get_filename function and somehow return the string literal "main.cpp", for example, instead of returning a pointer of that substring. Essentially, I want this to compile down so that the final binary just has main.cpp in it, and nothing else part of the __FILE__ macro. Is this possible?

CodePudding user response:

Because you don't want the full __FILE__ path in the final binary, we must copy the string to a std::array:

constexpr auto get_filename()
{
    constexpr std::string_view filePath = __FILE__;
    constexpr auto count = filePath.rfind("\\");

    static_assert(count != std::string::npos);
    
    std::array<char, count> fileName{};
    std::copy(filePath.data()   count   1, filePath.data()   filePath.size(), fileName.data());

    return fileName;
}

And specify constexpr when calling the get_filename function:

constexpr auto fileName = get_filename();
std::cout << fileName.data();

Alternatively, since C 20, you could use consteval to force it to be evaluated at compile time:

consteval auto get_filename();

Here's the test on godbolt, it uses printf instead of std::cout for a shorter asm.

CodePudding user response:

Like this my code is in a file called .\some_path\main.cpp (windows path style):

#include <string_view>
#include <iostream>

static constexpr std::string_view get_filename()
{
    std::string_view name{ __FILE__ };

    auto pos = name.find_last_of('\\'); // or '/' on linux
    if (pos != std::string::npos)
    {
        return std::string_view{ name.begin()   pos   1, name.end() };
    }

    return name;
}


int main()
{
    static_assert(get_filename() == "main.cpp");

    std::cout << get_filename();

    return 0;
}
  • Related