c++visual-c++constexprcompile-time

How to return compile-constant string literal with C++ constexpr function


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?


Solution

  • 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.