Reputation: 68698
Suppose I want to write a C++1y/14 constexpr function that performs integer square root:
constexpr int constexpr_isqrt(int x);
I want to perform a sanity check to make sure that x
is non-negative:
constexpr int constexpr_isqrt(int x)
{
if (x < 0)
???
...
}
What should I write in ???
above?
Ideally if the function is evaluated in constant context it should cause a compile-time error, and if called at run-time with a run-time error (eg abort or thrown exception).
Upvotes: 12
Views: 2325
Reputation: 10355
You're in luck, there is a way! Even in C++11! Use exceptions:
#include <iostream>
#include <stdexcept>
constexpr int foo(int a)
{
return (a >= 0) ? a : throw std::invalid_argument("Negative!");
}
template <int n>
struct Foo
{
};
int main()
{
Foo<foo(1)> f1(); // fine, guaranteed compile time
Foo<foo(-1)> f2(); // bad, compile time error
foo(1); // fine, not necessarily at compile time
try
{
foo(-1); // fine, definitively not at compile time
}
catch ( ... )
{
}
return 0;
}
Demo: http://ideone.com/EMxe2K
GCC has a rather good error message for the disallowed case:
prog.cpp: In function ‘int main()’:
prog.cpp:17:12: in constexpr expansion of ‘foo(-1)’
prog.cpp:6:63: error: expression ‘<throw-expression>’ is not a constant-expression
return (a >= 0) ? a : throw std::invalid_argument("Negative!");
For a C++1y constexpr function that looks like
constexpr foo(int a)
{
if ( a < 0 )
{
// error!
}
++a;
//something else
return a;
}
you can use the above pattern by introducing a new function:
constexpr foo_positive(int a)
{
++a;
//something else
return a;
}
constexpr int foo(int a)
{
return (a >= 0) ? foo_positive(a) : throw std::invalid_argument("Negative!");
}
Or you simply write
constexpr foo(int a)
{
if ( a < 0 )
{
throw std::invalid_argument("Negative!");
}
++a;
//something else
return a;
}
Upvotes: 12