6

I'm writing a constexpr code and I would like to inspect computed values at compile time.

The usual trick is to do something like this:


struct ReturnValue
{
    int value1;
    int value2;
};

constexpr ReturnValue doTheComputation() 
{
    return { .value1 = 10, .value2 = 20 };
}


template< auto t > struct p;

p< doTheComputation() > foo;

This gives a nice compile error:

implicit instantiation of undefined template 'p<ReturnValue{10, 20}>'

and I can see the value of the result.

However, this does not work for non-structural types, like std::string_view, std::string, or anything that resembles a string, as such types are not allowed to be NTTP.

Non-working example with std::string_view: https://godbolt.org/z/da8W557nK

Non-working example with char const *: https://godbolt.org/z/5Mvqfx95q

Even if I use char const[ some_large_numer ] to ensure the message fits, like this, instead of a string, I get the ASCII values listed as template parameters:

implicit instantiation of undefined template 'p<ReturnValue{{115, 111, 109, 101, 32, 115, 101, 99, 114, 101, ...}}>

Are there any tips or tricks to print values of non-structural types at compile-time (as results of constexpr functions)?

I've seen an unofficial patch for GCC that apparently solves that (I haven't tested it), but I'm searching for a solution for clang (Apple-clang from Xcode 15 or newer and LLVM 18 or newer).

10
  • 1
    Unrelated: You can reduce return {.value1 = 10, .value2 = 20} to just return {10,20} Commented Jun 26 at 11:28
  • 1
    Just add a proper formatter and use p<std::format("{}", doTheComputation())>. Commented Jun 26 at 11:46
  • Thank you for the trick, sometimes I need quick way to compute sizeof() or offsetof.
    – prapin
    Commented Jun 26 at 12:46
  • 1
    @user12002570 It is still helpful to a human reader if the definition of ReturnValue is far away (for example in another file). I prefer being explicit. Commented Jun 26 at 14:46
  • 1
    I mean for a reader, not a writer. return Rectangle{.width=3, .height=4}; is clearer than return Rectangle{3,4} for someone that reads the code. I'm not talking about writing it. Commented Jun 26 at 14:49

1 Answer 1

3

Inspired by the idea by @WeijunZhou from comments to the question, I searched more. I discovered that C++26 has a flavor of static_assert that allows the second parameter to be a string-like result of constexpr computation (C++ reference).

Unfortunately, std::format is not constexpr-friendly even in C++26 (cpp-reference confirms this), but I can always write my formatting function that outputs string-like literal object (according to the specification, it only needs to provide .size() and .data() functions), so I came up with the following solution:

#include <string_view>
#include <string>

struct ReturnValue
{
    std::string_view data;
    std::string      data2;
};

constexpr ReturnValue doTheComputation() 
{
    return { .data = "some secret message", .data2 = "owned data" };
}

constexpr std::string format( ReturnValue const & val )
{
    std::string result{ val.data };
    result += ", additional data: ";
    result += val.data2;
    return result;
}

static_assert( false, format( doTheComputation() ) );

This appears to work on LLVM 18, but not yet on Apple-Clang shipped with Xcode 15.4 (I still need to test with Xcode 16 beta).

In general, it's a workable solution, but I would still be happier if somebody came up with a solution that I could use on Xcode 15.4.

1
  • Apparently, this feature will not be ready in Xcode 16, according to this Apple document.
    – DoDo
    Commented Jun 26 at 16:27

Not the answer you're looking for? Browse other questions tagged or ask your own question.