19

It would be useful to have 'constexpr' parameters in order to distinguish compiler-known values and so be able to detect errors at compile time. Examples:

int do_something(constexpr int x)
{
  static_assert(x > 0, "x must be > 0");
  return x + 5;
}

int do_something(int x)
{
  if(x > 0) { cout << "x must be > 0" << endl; exit(-1); }
  return x + 5;
}

int var;

do_something(9); //instance 'do_something(constexpr int x)' and check arg validity at compile time

do_something(0); //produces compiler error

do_something(var); //instance 'do_something(int x)'

This is invalid code for now. Can somebody explain to me why this can't be implemented?

EDIT:

Using templates users have to always pass literals as template arguments and not as function ones which is very uncomfortable:

template<int x>
int do_something()
{
  static_assert(x > 0, "x must be > 0");
  return x + 5;
}

int do_something(int x)
{
  if(x > 0) { cout << "x must be > 0" << endl; exit(-1); }
  return x + 5;
}

int var;

do_something(9); //instance 'do_something(int x)' and doesn't check validity at compile time

do_something(0); //same as above, if check was performed - compiler error should occur

do_something<9>(); //instance template 'do_something<int>()'

do_something<0>(); //produces compiler error

do_something(var); //instance 'do_something(int x)'
Boann
  • 48,794
  • 16
  • 117
  • 146
AnArrayOfFunctions
  • 3,452
  • 2
  • 29
  • 66
  • 1
    Cant you already do that with a template? More specifically with non-type template parameters? – Borgleader Dec 21 '14 at 17:38
  • Then the user of my function should supply different syntax for calling it depending on if the parameter is compile-time known. – AnArrayOfFunctions Dec 21 '14 at 17:40
  • an assert() could presumably be optimized out in the event that a constexpr value was passed in. – Cory Nelson Dec 21 '14 at 17:52
  • gcc 4.8.3 (cygwin x64) with -std=c++11 does not recognize the use of a constexpr parameter. Is that standard? I am not experienced with C++ 14 but is it possible that the constexpr-ness is a property of the function which may or may not be computed at compile time, depending on the (implicit) constexpr-ness of the parameters? – Peter - Reinstate Monica Dec 21 '14 at 17:55
  • 1
    `constexpr` is not a type qualifier. Do you want it to be? We already have `const` and `volatile` that give 4 combinations together. Do we really need any more? – n. m. could be an AI Dec 21 '14 at 17:55
  • @PeterSchneider No this is not in the standard. The OP is asking *why*. – n. m. could be an AI Dec 21 '14 at 17:56
  • @n.m. Oh. I see. I understood that the function definition and call with the argument 9 compiles but the argument 0 fails. I'd then say "It **would be** useful to have ..." – Peter - Reinstate Monica Dec 21 '14 at 17:57
  • "_Using templates users should assure that literals are always passed as template arguments and not as function ones which is very uncomfortable_" - you can use preprocessor: `#define DO_SOMETHING(...) do_something<__VA_ARGS__>()` – GingerPlusPlus Dec 21 '14 at 19:13

2 Answers2

4

If I'm understanding what you're trying to do correctly, the functionality you are requesting is already available. It's not the most elegant, but I think this is good enough.

You would like to call a function at compile-time and run-time with the same syntax, and have it evaluate at compile-time if possible, otherwise it should evaluate at run-time. You need assertions to be evaluated on the function regardless of when it is called.

I believe that this will do what you want:

constexpr int do_something(int x)
{
    if(x <= 0)
    {
        std::cout << "x must be > 0" << std::endl; exit(-1);
    }
    return x + 5;
}

constexpr int compiletime_good = do_something(5);
constexpr int compiletime_bad = do_something(0);    // Fails at compile-time

int runtime_good = do_something(5);
int runtime_bad = do_something(0);    // Fails at runtime

constexpr int val_good = 5;
constexpr int val_bad = 0;

do_something(val_good);
do_something(val_bad);    // Fails at run-time

int valrun_good = 5;
int valrun_bad = 0;

do_something(valrun_good);
do_something(valrun_bad);    // Fails at run-time

The trick here is to fail at compile time in a way that doesn't require static_assert, and will also fail at runtime.

Michael Gazonda
  • 2,720
  • 1
  • 17
  • 33
  • 1
    Which will require each instance of 'do_something' to be called where 'constexpr' is expected which isn't any better than using templates. – AnArrayOfFunctions Dec 21 '14 at 18:43
  • 1
    @FISOCPP Fair enough. I'm guessing the reason we don't have an explicit way to include constexpr parameters in the way you're asking is that no one's gone to the trouble to write up and get a proposal pushed through. I'd like to see that happen, but it sounds like a lot of work. – Michael Gazonda Dec 21 '14 at 18:48
  • 1
    One should of course use an existing facility for reporting an assertion failure, not sprinkle `std::exit()` calls throughout the codebase. Otherwise this is very good. – Ben Voigt Dec 21 '14 at 18:50
  • 1
    The only way to improve on it would be to do something that's likely to cause a compiler warning if the parameters are compile-time constants, even if not run in `constexpr` context. Perhaps integral divide-by-zero? `1 / (x > 0);` Of course whether a compiler warns about the UB is very compiler-specific. – Ben Voigt Dec 21 '14 at 18:53
  • @BenVoigt Thanks, I was merely using the code from OP, so I used their runtime failure code. – Michael Gazonda Dec 21 '14 at 18:53
  • @MichaelGazonda: Fair enough. – Ben Voigt Dec 21 '14 at 18:54
  • You could add an example line, where `do_something(val_bad);` is evaluated at compile-time (e.g. by assigning to constexpr l-value) to show that the compile-time parameters can be variables. – Sebastian Jan 16 '22 at 02:52
-2

While this sounds great in theory, it's not that useful in the real world. Most arguments to functions are not compile time constants, and many constraints are not exactly known at compile time either.

To specify and implement such overloading would be a significant amount of work, and it wouldn't be used that much. When you actually have compile time bounds and arguments, you can usually evaluate the entire function at compile time, which means that overloading is not necessary.

Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157
  • 1
    This doesn't specifically answer WHY, which is what the question asks. – AStopher Dec 21 '14 at 18:27
  • 1
    @cybermonkey I obviously disagree. I tried to explain why the feature isn't in the standard by describing why it isn't useful enough to justify the effort. Unlike the other answer to this question, which doesn't answer the why in any way, shape or form, but just tries to describe a workaround (i.e. puts actual code that just shows off what I write in my second paragraph). – Sebastian Redl Dec 22 '14 at 09:47
  • The trend for the standard library is to make 'everything' constexpr so that it can be used the same way at compile-time. Compile-time computations get more and more involved and the allowed C++ constructs more and more complete. E.g. look at this talk with font rendering done at compile-time https://youtu.be/MdrfPSUtMVM – Sebastian Jan 16 '22 at 03:01