Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
161 views
in Technique[技术] by (71.8m points)

c++ - single expression helper for compile-time enforced constexpr function evaluation possible?

@cyberpunk_ is trying to achieve something and made some questions about it but all the chase boils down to this:

Is it possible to build a tool to enforce compile-time evaluation of a constexpr function?

int f(int i) {return i;}
constexpr int g(int i) {return i;}

int main()
{
    f(at_compilation(g, 0));
    int x = at_compilation(g, 1);
    constexpr int y = at_compilation(g, 2);
}

In all situations, at_compilation enforce compilation-time evaluation of g.

at_compilation doesn't need to be in this form.

Requirements

  • Allow any (numerical native) literal type as input for the constexpr function.
    • this could also be hardcoded based on the function arguments types.
  • Allow any (numerical native) literal type as output, which is the result of the constexpr function call.
    • this could also be hardcoded based on the function return type.

Desirables

  • Reduced macro usage but don't be afraid of using.
  • Be general (not type hardcoded).
  • Support any literal type. At last any numerical native literal type is a requirement.

Related Questions:

  1. When does a constexpr function get evaluated at compile time?
  2. Forcing a constant expression to be evaluated during compile-time?
  3. Passing any function as a template parameter?
  4. Where in the C++11 standard does it specify when a constexpr function can be evaluated during translation?

Answers with relevant code samples:

  • 1
  • 2
  • 3 (this one has an illustrative AT_COMPILATION macro)

All the code samples have limitations regarding the requirements.

A clear explanation for how this is unfeasible in C++ is also a good answer.

I suspect it's impossible based on @K-ballo / @Herb Sutter answer which states "and the result is used in a constant expression as well". This was not part of my former conception about constexpr functions, I firstly thought that just passing literals (or other compile-time input) as arguments would suffice to guarantee (by standard) it to be evaluated at compilation-time.

It's already assumed constexpr function's purpose is that they can fit in constant expression situations when necessary, like in array bounds. That's OK. Given that, this question is about a hack on using them just as a tool for compile time calculation. Whether it's a good or bad thing to do should not matter.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I believe that it's impossible because the compiler is only required to compute values that are used at compile-time, and there is no generic expression that can use every part of a value of class type. Computations that initialize private members might even be impossible to force, as you would depend on a public constexpr member function to use the result.

If you could access the object representation by

static_cast< char const * >( static_cast< void const * >( & const_value ) )

then it would be possible to checksum the result of the computation (and use the result as an integral constant expression), forcing the compiler to perform every calculation that isn't moot. But the cast from void * to char * is disallowed in a constant-expression, and likewise attempting to accomplish the same with a union. Even if it were allowed, if the constructor left one byte uninitialized, using an uninitialized value is also forbidden in a constant-expression.

So, even if C++ had better tools for introspection, it would still be impossible to recover the work performed by a constexpr function in order to artificially use some members but not others.

Just to be clear (even if it repeats the question), there's no reason to want this. The language already requires a check that everything can be computed at compile time, if needed, and the only effect of forcing the compiler to non-lazily compute pure values would be to make it slower and use more memory.

Edit (question was radically altered)

If you have several functions returning scalar type, and want to ensure that some of them work as constant expressions under certain arguments, then write test cases using static_assert.

constexpr int g(int i) {return i;}
int i = 5;
static_assert( g( 3 ) == 0, "failure 1" );
static_assert( g( i ) == 5, "failure 2" );

If you don't want to fix the result values, then discard them. (Unfortunately, GCC may optimize out the non-constant part of such an expression, so you might need to do something more baroque on that platform.

static_assert( g( i ) == 5 || true, "failure only if not constexpr" );

As for encapsulating this into a macro, the other linked questions seem to address a lot. If you want to expand one of those answers or to fix a particular bug, it would be better to explain the bug rather than ask us to read so much literature and start from scratch.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...