Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

constexpr function parameter and static_assert

38 views
Skip to first unread message

Ian Collins

unread,
Mar 4, 2016, 5:54:37 AM3/4/16
to
This one bugs me:

A parameter for a constexpr function must be a constant expression but..

You can't use static_assert to check the value in the function. Defect
in the standard?

constexpr unsigned f( unsigned n )
{
static_assert( n < 1000, "Ops" ); return 0;
}

g++ -std=c++17 x.cc

x.cc:26:38: error: ‘n’ is not a constant expression

--
Ian Collins

David Brown

unread,
Mar 4, 2016, 7:10:50 AM3/4/16
to
The function f() can be called with n that is not known at compile-time,
in which case the static_assert cannot be evaluated.

I suspect the best you can do is something like:

extern void __attribute__((error("Compile time check failed")))
compileTimeCheckFailed(void);

constexpr unsigned f(unsigned n) {
if (__builtin_constant_p(n)) {
if (!(n < 1000)) {
compileTimeCheckFailed();
}
} else {
if (!(n < 1000)) {
throw runTimeCheckFailed;
}
}
return 0;
}


Öö Tiib

unread,
Mar 4, 2016, 9:02:27 AM3/4/16
to
> !(n < 1000)) ? (void) : throw runTimeCheckFailed;
> }
> }
> return 0;
> }

Calling non-constexpr from constexpr function (like
that 'compileTimeCheckFailed') and/or throwing from
constexpr function without using ?: operator should not
compile AFAIK. Maybe something like that:

constexpr int f(int n)
{
(n < 1000) ? true : throw 42;
// ... do what you need
return 0;
}

int main(int argc, char **argv)
{
constexpr int i = 5000;
int k = 6000;
const int m = 6;
const int n = argc;

constexpr int a = f(i); // <- compiler error
const int b = f(k); // <- throws 42
constexpr int c = f(m); // works OK
const int d = f(n); // works OK
}

Ian Collins

unread,
Mar 4, 2016, 4:09:40 PM3/4/16
to
On 03/05/16 03:02, Öö Tiib wrote:
>
> Calling non-constexpr from constexpr function (like
> that 'compileTimeCheckFailed') and/or throwing from
> constexpr function without using ?: operator should not
> compile AFAIK. Maybe something like that:
>
> constexpr int f(int n)
> {
> (n < 1000) ? true : throw 42;
> // ... do what you need
> return 0;
> }

That is basically the fiddle I came up with. The compiler errors are a
little obscure, but a comment fixes that. I added This:

constexpr int checkRange( int n ) {
(n < 1000) ? true : throw 0; return n; }

constexpr int f( int n ) { checkRange( n ); return n; }

It looks like the latest g++ has trouble spotting this in some
conditions, for example given these two lines:

constexpr int x {f(1000)};
char buf[f(8000)];

g++ >=5 spots the first as an error, but not the second. g++ 4.9 just
spits the dummy and runs.

Oracle CC spots them both:

Error: Initializer for constexpr variable x must be a constant expression.
Error: An integer constant expression is required within the array
subscript operator.

--
Ian Collins

Öö Tiib

unread,
Mar 4, 2016, 5:40:00 PM3/4/16
to
On Friday, 4 March 2016 23:09:40 UTC+2, Ian Collins wrote:
> On 03/05/16 03:02, Öö Tiib wrote:
> >
> > Calling non-constexpr from constexpr function (like
> > that 'compileTimeCheckFailed') and/or throwing from
> > constexpr function without using ?: operator should not
> > compile AFAIK. Maybe something like that:
> >
> > constexpr int f(int n)
> > {
> > (n < 1000) ? true : throw 42;
> > // ... do what you need
> > return 0;
> > }
>
> That is basically the fiddle I came up with. The compiler errors are a
> little obscure, but a comment fixes that. I added This:
>
> constexpr int checkRange( int n ) {
> (n < 1000) ? true : throw 0; return n; }

More often people merge there like:

constexpr int checkRange( int n ) {return (n < 1000) ? n : throw 0;}

>
> constexpr int f( int n ) { checkRange( n ); return n; }
>
> It looks like the latest g++ has trouble spotting this in some
> conditions, for example given these two lines:
>
> constexpr int x {f(1000)};
> char buf[f(8000)];
>
> g++ >=5 spots the first as an error, but not the second. g++ 4.9 just
> spits the dummy and runs.

The g++ has some sort of variable-length automatic arrays extension
so it somehow weasels out using that on second case I suspect.

>
> Oracle CC spots them both:
>
> Error: Initializer for constexpr variable x must be a constant expression.
> Error: An integer constant expression is required within the array
> subscript operator.

Yes, compiler makers are humans too and sometimes mix up when it
is "ill-formed" so they have to diagnose and when it is "undefined
behavior" so they may screw us.
The constexpr is relatively new so we have to calmly fire the bugs
for some years.

Ian Collins

unread,
Mar 4, 2016, 5:55:45 PM3/4/16
to
On 03/05/16 11:39, Öö Tiib wrote:
> On Friday, 4 March 2016 23:09:40 UTC+2, Ian Collins wrote:

>> constexpr int f( int n ) { checkRange( n ); return n; }
>>
>> It looks like the latest g++ has trouble spotting this in some
>> conditions, for example given these two lines:
>>
>> constexpr int x {f(1000)};
>> char buf[f(8000)];
>>
>> g++ >=5 spots the first as an error, but not the second. g++ 4.9 just
>> spits the dummy and runs.
>
> The g++ has some sort of variable-length automatic arrays extension
> so it somehow weasels out using that on second case I suspect.

Good spot, adding -pedantic (almost) does the trick:

warning: ISO C++ forbids variable length array ‘buf’ [-Wvla]
char buf[f(8000)];

So you would need both -pedantic and -Werror to catch this case.

--
Ian Collins

Alf P. Steinbach

unread,
Mar 5, 2016, 3:04:53 AM3/5/16
to
On 04.03.2016 22:09, Ian Collins wrote:
>
> constexpr int checkRange( int n ) {
> (n < 1000) ? true : throw 0; return n; }
>
> constexpr int f( int n ) { checkRange( n ); return n; }

This may possibly compile as C++17, even, I don't know, C++14. But not
C++11. Can't have more than one non-declaration statement (a.k.a.
"command" in BCPL), and that one must be a return statement. In C++11.

So, for compiler compatibility, which is generally a Goood Idea, I'd
write e.g.

constexpr auto range_checked( int const n )
-> int
{ return (n < 1000? n : throw 0); }


Cheers & hth.,

- Alf

0 new messages