Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why 'constexpr' parameters are not allowed?

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)'
like image 795
AnArrayOfFunctions Avatar asked Dec 21 '14 17:12

AnArrayOfFunctions


Video Answer


1 Answers

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.

like image 69
Michael Gazonda Avatar answered Sep 20 '22 09:09

Michael Gazonda