-3

I want to disable a function for any compile-time evaluated argument (a literal, or something that comes from a constexpr expression). Is that possible?

For integers, it is possible to do the opposite use non-type template arguments, but that would also change the call syntax.

I am playing around with strict integers, that needs to be initiated somehow. Current rule for handling bad input:

  • If the source value is only known at runtime, and a narrowing cast would destroy the interpretation (not the bits), an exception is thrown

  • If the source value is known at compile time, and it wouldn't fit there should be a compilation error.

My idea was to disable the constructor that accepts a wider type for all constexpr arguments.

By strict, I mean that only value-preserving conversions are allowed:

Assume N >= M

  • int<M> to int<N> Always OK
  • uint<M> to uint<N> Always OK

For everything else:

  1. There should be a compilation error if the source value is known at compile-time.
  2. If the value is not known during compilation, see if a conversion would work properly, otherwise throw an exception.

For case (1), using the constexpr-throw trick does not work: Consider the following (non-constexpr context):

// Will compile, but it shouldn't. Instead of not compiling it will throw an exception.
int<16> foo(12345); 

// Will compile. Whatever the type of some_value_from_outside is, 
// check that it fits at runtime. If it does not, throw an exception.
int<16> thisIsFine(some_value_from_outside);

What would be ideal is overload resolution with respect to constexpr argument, which does not exists, so I am trying to find the best workaround.

user877329
  • 6,717
  • 8
  • 46
  • 88

2 Answers2

0

I want to disable a function for any compile-time evaluated argument

It is not possible, and it makes no sense (in general).

In practice, with the as-if rule, most optimizing compilers will generate the same code for f(2); and { int i=2; f(i); } since both have the same semantics.

With GCC and also Clang, you might use __builtin_constant_p

With GCC, you might spend weeks or months coding your GCC plugin which would detect (and emit a diagnostic for) calls to function with compile time argument (e.g. you could implement your new function attribute in a plugin). But that won't change overloading or typing rules. And I really don't recommend making a plugin in your particular case.

Your question stays unclear, and it looks like you want something C++ does not provide. BTW int<16> is not legal C++ because int is not a template. Maybe you want std::int16_t ?

Did you consider some other approach, perhaps generating C++ code from something else, maybe using some other preprocessor (e.g. GPP or m4) or C++ code generator (your own one, perhaps; Qt moc or GNU bison or SWIG might be inspirational).

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • `__buildin_constant_p` does not solve the problem, as you cannot feed it into `static_assert`. – user877329 Mar 25 '18 at 13:27
  • @BasilieStarynkevitch StackOverflow understand the question, and suggests a look at https://stackoverflow.com/questions/18981752/c-compile-time-check-function-arguments?rq=1, which is basically what I need to do. – user877329 Mar 30 '18 at 14:40
0

I accept that for now, there is now possibility to check that an expression is constexpr, neither through overloads (might be interesting to have), or any other approach. However, for reference I should list the current workarounds here:

  1. Declare constants as constexpr and use the following idiom

    value fits in type ? cast to type : throw CastException
    

    This wil only compile if value fits in type, since otherwise the function is not constexpr.

  2. Use an alternative templated factory method as mentioned c++ compile-time check function arguments.

I will go for (1), since it does not require different syntax for the constexpr case. Also, I think it is good practice to name constants anyway.

user877329
  • 6,717
  • 8
  • 46
  • 88