Home > Mobile >  Printing a compile-time string_view
Printing a compile-time string_view

Time:08-10

Say I have a metafunction that returns a std::string_view

template<typename T>
struct type_to_string;

template <typename T>
constexpr std::string_view type_to_string_v = type_to_string<T>::value;

and a string_view resulting from this:

constexpr auto sv = type_to_string_v<very_complex_expression>;

Is there any way to print the value of this string at compile-time? (ie. as part of some compiler error message or static assert)

CodePudding user response:

Here's a modification of OP's solution that produces a somewhat more readable message with gcc. Unfortunately, with clang the message is rather less readable, and MSVC doesn't work at all (due to a compiler bug I suppose).

#include <cstdlib>
#include <algorithm>
#include <string_view>
#include <utility>

template <size_t N> struct FS {             // fixed size string
  char chars[N   1] = {};
  constexpr FS(const char (&str)[N   1]) {
      std::copy_n(str, N   1, chars); 
  }
};

template <size_t N> FS(const char (&str)[N])->FS<N - 1>;

template<typename T>
struct type_to_string;

template<>
struct type_to_string<int> { constexpr static auto value = "integer"; };

template <auto>
constexpr bool string_value = false;

template<FS fs>                             // size will be deduced
void compile_time_display() {
        static_assert(string_value<fs>);
}

int main()
{
    constexpr std::string_view sv = type_to_string<int>::value;
    constexpr size_t n = sv.size();
    constexpr auto indices = std::make_index_sequence<n>();

    [&] <std::size_t... I>
        (std::index_sequence<I...>)
        {
            static constexpr char text[] { (char)sv.at(I)..., 0 };
            compile_time_display<text>();    // the char array will convert to FS

        }(indices);
}

The message shown by gcc reads:

main.cc: In instantiation of ‘void compile_time_display() 
     [with FS<...auto...> fs = FS<7>{"integer"}]’
...
main.cc:26:23: note: ‘string_value<FS<7>{"integer"}>’ evaluates to false

CodePudding user response:

C has no mechanism to "print" anything at compile-time. Constant evaluation has no input or output mechanism. static_asserts can be used to display messages, but they specifically take string literals.

CodePudding user response:

It turns out that this can be done in a relatively straightforward way by destructuring the string_view into a list of chars. Here's a complete example extending the setup from the original question:

#include <string_view>
#include <utility>

template<typename T>
struct type_to_string;

template<>
struct type_to_string<int> { constexpr static auto value = "integer"; };

template <char... T>
constexpr bool string_value = false;

template<char... c>
void compile_time_display() {
        static_assert(string_value<c...>);
}

int main() {
        constexpr std::string_view sv = type_to_string<int>::value;
        constexpr size_t n = sv.size();
        constexpr auto indices = std::make_index_sequence<n>();

        [&] <std::size_t... I>
           (std::index_sequence<I...>)
        {
                compile_time_display<sv.at(I)...>();
        }(indices);
}

Popular compilers display the string value prominently:

$ g   sv_to_array.cpp
sv_to_array.cpp: In instantiation of ‘void compile_time_display() [with char ...c = {'i', 'n', 't', 'e', 'g', 'e', 'r'}]’:
sv_to_array.cpp:26:36:   required from ‘main()::<lambda(std::index_sequence<I ...>)> [with long unsigned int ...I = {0, 1, 2, 3, 4, 5, 6}; std::index_sequence<I ...> = std::integer_sequence<long unsigned int, 0, 1, 2, 3, 4, 5, 6>]’
sv_to_array.cpp:27:3:   required from here
sv_to_array.cpp:15:23: error: static assertion failed
   15 |         static_assert(string_value<c...>);
      |                       ^~~~~~~~~~~~~~~~~~
sv_to_array.cpp:15:23: note: ‘string_value<'i', 'n', 't', 'e', 'g', 'e', 'r'>’ evaluates to false
$ clang   sv_to_array.cpp -std=c  20
sv_to_array.cpp:15:2: error: static_assert failed due to requirement 'string_value<'i', 'n', 't', 'e', 'g', 'e', 'r'>'
        static_assert(string_value<c...>);
        ^             ~~~~~~~~~~~~~~~~~~
sv_to_array.cpp:26:3: note: in instantiation of function template specialization 'compile_time_display<'i', 'n', 't', 'e', 'g', 'e', 'r'>' requested here
                compile_time_display<sv.at(I)...>();
                ^
1 error generated.

  • Related