Topic: Instantiating NonType templates within constexpr functions (Legal?)


Author: Marc <marc.glisse@gmail.com>
Date: Fri, 22 May 2009 02:11:46 CST
Raw View
On May 20, 2:11 pm, daniel.krueg...@googlemail.com wrote:
> On 20 Mai, 05:48, Jonas Persson <l.j.pers...@gmail.com> wrote:
> > How about if the function is declared as
> > constexpr int foo(constexpr int x) {
> >  ...
> > }
> > Is that a legal way to force compile time arguments and compile-time evaluation?
>
> No, it isn't, see [dcl.constexpr]/1:
>
> "[..] [ Note: function parameters cannot be declared constexpr.   end
> note ][ Example: [..]
>    int next(constexpr int x) { // error
>    return x + 1;
>
> } [..] "

This looks like a pain. It means I can't overload a function on
whether its arguments are constants. For a given function, I then have
to chose whether I want to make it constexpr and work within the very
restrictive constraints (it is a good thing recursion and ?: are
allowed at least) or give up on the constexpr thing and write an
efficient implementation.

I used to hope constexpr would be able to replace some of the most
basic uses of the gnu extension __builtin_constant_p, but I now (after
reading the paper that introduced constexpr) understand better that
this is not part of the goal.

A possibility to declare (not define) constexpr functions (only if the
compiler provides them, either as builtin or because it allows
plugins) would also have been nice. Currently the draft says constexpr
should only be applied to function definitions, but the library
section contains plenty of examples with constexpr applied to
declarations, which is confusing.


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: daniel.kruegler@googlemail.com
Date: Fri, 22 May 2009 11:37:38 CST
Raw View
On 22 Mai, 10:11, Marc <marc.gli...@gmail.com> wrote:
> On May 20, 2:11 pm, daniel.krueg...@googlemail.com wrote:
>
> > On 20 Mai, 05:48, Jonas Persson <l.j.pers...@gmail.com> wrote:
> > > How about if the function is declared as
> > > constexpr int foo(constexpr int x) {
> > >  ...
> > > }
> > > Is that a legal way to force compile time arguments and compile-time evaluation?
>
> > No, it isn't, see [dcl.constexpr]/1:
>
> > "[..] [ Note: function parameters cannot be declared constexpr.  end
> > note ][ Example: [..]
> >    int next(constexpr int x) { // error
> >    return x + 1;
> > } [..] "
>
> This looks like a pain. It means I can't overload a function on
> whether its arguments are constants. For a given function, I then have
> to chose whether I want to make it constexpr and work within the very
> restrictive constraints (it is a good thing recursion and ?: are
> allowed at least) or give up on the constexpr thing and write an
> efficient implementation.

Why do you consider recursion and the conditional operator as bad
choices? We use them in recursive template specializations all the
time.

> Currently the draft says constexpr
> should only be applied to function definitions, but the library
> section contains plenty of examples with constexpr applied to
> declarations, which is confusing.

These are actually two different things:

a) You cannot take library declarations literally. If e.g. the
standard requires a definition here which isn't presented this
doesn't necessarily mean that this is a library issue. One
could consider to write something like /see below/ here,
but this is an editorial thing.

b) Whether constexpr functions (at least member functions) should
be possible as non-defining declarations is currently discussed, see

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#699

Greetings from Bremen,

Daniel Kr  gler


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Gabriel Dos Reis <gdr@cs.tamu.edu>
Date: Sat, 23 May 2009 11:02:46 CST
Raw View
Marc <marc.glisse@gmail.com> writes:

| On May 20, 2:11 pm, daniel.krueg...@googlemail.com wrote:
>> On 20 Mai, 05:48, Jonas Persson <l.j.pers...@gmail.com> wrote:
>> > How about if the function is declared as
>> > constexpr int foo(constexpr int x) {
>> >  ...
>> > }
>> > Is that a legal way to force compile time arguments and compile-time evaluation?
>>
>> No, it isn't, see [dcl.constexpr]/1:
>>
>> "[..] [ Note: function parameters cannot be declared constexpr.      end
>> note ][ Example: [..]
>>    int next(constexpr int x) { // error
>>    return x + 1;
>>
>> } [..] "
>
| This looks like a pain. It means I can't overload a function on
| whether its arguments are constants. For a given function, I then have
| to chose whether I want to make it constexpr and work within the very
| restrictive constraints (it is a good thing recursion and ?: are
| allowed at least) or give up on the constexpr thing and write an
| efficient implementation.

If you already have an efficient function which is not non-constexpr,
you are good.  No?

| I used to hope constexpr would be able to replace some of the most
| basic uses of the gnu extension __builtin_constant_p, but I now (after
| reading the paper that introduced constexpr) understand better that
| this is not part of the goal.

that paper gave real world motivating examples for constexpr.

| A possibility to declare (not define) constexpr functions (only if the
| compiler provides them, either as builtin or because it allows
| plugins) would also have been nice.

The standard does not know about plugins so it would be difficult to
adequately talk about a feature for an unknown purpose.  And it
certainly does not prohibit a C++ implementation from providing extensions.


| Currently the draft says constexpr
| should only be applied to function definitions, but the library
| section contains plenty of examples with constexpr applied to
| declarations, which is confusing.

That is because the library specification does not provide
implementation -- only specification.  The constexpr marker is a
specification that the implementation must make the function behave as if
defined constexpr.  And since the standard library is not required to be
written in C++, there is no harm or confusion done.



--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Marc <marc.glisse@gmail.com>
Date: Sat, 23 May 2009 11:50:23 CST
Raw View
On May 22, 10:37 am, daniel.krueg...@googlemail.com wrote:
> On 22 Mai, 10:11, Marc <marc.gli...@gmail.com> wrote:
> > On May 20, 2:11 pm, daniel.krueg...@googlemail.com wrote:
> > > On 20 Mai, 05:48, Jonas Persson <l.j.pers...@gmail.com> wrote:
> > > > How about if the function is declared as
> > > > constexpr int foo(constexpr int x) {
> > > >  ...
> > > > }
> > > > Is that a legal way to force compile time arguments and compile-time evaluation?
>
> > > No, it isn't, see [dcl.constexpr]/1:
>
> > > "[..] [ Note: function parameters cannot be declared constexpr.   end
> > > note ][ Example: [..]
> > >    int next(constexpr int x) { // error
> > >    return x + 1;
> > > } [..] "
>
> > This looks like a pain. It means I can't overload a function on
> > whether its arguments are constants. For a given function, I then have
> > to chose whether I want to make it constexpr and work within the very
> > restrictive constraints (it is a good thing recursion and ?: are
> > allowed at least) or give up on the constexpr thing and write an
> > efficient implementation.
>
> Why do you consider recursion and the conditional operator as bad
> choices? We use them in recursive template specializations all the
> time.

I consider them great choices (I didn't think my sentence implied the
opposite) that make perfect sense for compile-time operations. What I
am complaining about is that this implementation meant to be easy for
the compiler to evaluate at compile-time has to be the same as the
implementation meant to be evaluated fast at runtime (where using
variables, loops, etc could help). Well, if we only make simple
constexpr functions, with a little bit of care writing the functions,
this may be acceptable. I guess I am mostly disappointed that this is
a missed occasion to introduce some form of __builtin_constant_p.

> > Currently the draft says constexpr
> > should only be applied to function definitions, but the library
> > section contains plenty of examples with constexpr applied to
> > declarations, which is confusing.
>
> These are actually two different things:
>
> a) You cannot take library declarations literally.

I know, there is explicit warning about this in the standard (it is
still confusing though).

> b) Whether constexpr functions (at least member functions) should
> be possible as non-defining declarations is currently discussed, see
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#699

It looks like it is only mentioning declarations that are meant to be
followed by a definition. For instance I am wondering how to make
std::abs(int) a constexpr function. Or even std::cos(double) (ignoring
the rounding issues) where you obviously won't write an implementation
in the headers but the compiler could be allowed to have one. But
since this would only be for implementation defined stuff, I guess it
does not really matter.

Thank you for your explanations.


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Gabriel Dos Reis <gdr@cs.tamu.edu>
Date: Sun, 24 May 2009 15:12:26 CST
Raw View
Marc <marc.glisse@gmail.com> writes:

[...]

|                         I guess I am mostly disappointed that this is
| a missed occasion to introduce some form of __builtin_constant_p.

I have the suspicion that a concrete proposal motivated by real world
problems may be more impactful that a simple expression of
disappointment about not picking some compiler extension.
Please note that my invitation is serious.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: SG <s.gesemann@gmail.com>
Date: Tue, 19 May 2009 10:02:45 CST
Raw View
On 18 Mai, 05:48, Faisal Vali <fais...@gmail.com> wrote:
> Consider class 'C' which is intended to be a template that results in
> a 'literal type':
>
> template<int N> struct C
> {
>   int n;
>   constexpr C(int n) : n(n) { }
>   constexpr operator int() { return N * n; }
> };
>
> Does any one know if the following code is well-formed? (i.e. where is
> the language that supports or forbids these contructs?)
>
> constexpr int foo(const int I)
> {
>   return I < 0 ? C<I>(I + 10) : foo(I - 1);
> }

This is ill-formed due to a number of reasons:
1. The variable 'I' can't be a template argument for C.
2. If I remember correctly constexpr functions are not allowed to
recurse. For compile-time recursion you'd still need templates.
3. The type of the "?:"-expression would be ambiguous. On the left
side of the colon is an expression of type C<I>. On the right side is
an expression of type int. Each type is implicitly convertible to the
other one => ambiguity.

> [...]
> Also, does anyone know where exactly it states when these constexpr
> functions get executed?

A constexpr is a normal function and can be invoked at runtime. In
case a constexpr function definition is well-formed and some specific
call to this function uses constant expressions for all arguments this
function will be evaluated at compile-time. There's a way to make sure
that a specific constexpr function invocation is done at compile-time:

   constexpr int foo(int x) {
     return 3*x+2;
   }

   int main() {
     constexpr int x = foo(42); // OK, computed at compile-time
   }

By declaring 'x' to be a constant expression the compiler will only
allow initializers that are also constant expressions. In this case
everything is fine (42 is a constant expression & foo is declared with
constexpr => foo(42) is also a constant expression). If you remove
'constexpr' in the definition of 'foo' or use some other argument for
foo that is not a constant expression the compiler will reject the
code -- probably with an error message like "Error: the initializer of
constexpr 'x' is not a constant expression". This is where const and
constexpr differ:

   int foo();

   int main() {
     const int a = 42;        // OK, compile-time
     const int b = foo();     // OK, run-time
     constexpr int c = 42;    // OK, compile-time
     constexpr int d = foo(); // Ill-formed, won't compile
   }


Cheers!
SG

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: wasti.redl@gmx.net
Date: Tue, 19 May 2009 10:43:28 CST
Raw View
On May 18, 5:48 am, Faisal Vali <fais...@gmail.com> wrote:
> Consider class 'C' which is intended to be a template that results in
> a 'literal type':
>
> template<int N> struct C
> {
>   int n;
>   constexpr C(int n) : n(n) { }
>   constexpr operator int() { return N * n; }
>
> };
>
> Does any one know if the following code is well-formed? (i.e. where is
> the language that supports or forbids these contructs?)
>
> constexpr int foo(const int I)
> {
>   return I < 0 ? C<I>(I + 10) : foo(I - 1);
> }

There are two things that are not allowed here. First, a constexpr
function must be legal even when not evaluated constexpr, and using
the parameter I as a template parameter is not legal. Second, the
function is recursive. I can't find the standard language forbidding
recursion though, so maybe they lifted this requirement. But you still
can't have a constexpr function that wouldn't be a legal non-constexpr
function.

Sebastian


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Jonas Persson <l.j.persson@gmail.com>
Date: Tue, 19 May 2009 21:48:55 CST
Raw View
SG skrev:
>>
>> Also, does anyone know where exactly it states when these constexpr
>> functions get executed?
>
> A constexpr is a normal function and can be invoked at runtime. In
> case a constexpr function definition is well-formed and some specific
> call to this function uses constant expressions for all arguments this
> function will be evaluated at compile-time. There's a way to make sure
> that a specific constexpr function invocation is done at compile-time:
>
>   constexpr int foo(int x) {
>     return 3*x+2;
>   }
>
>   int main() {
>     constexpr int x = foo(42); // OK, computed at compile-time
>   }

How about if the function is declared as

constexpr int foo(constexpr int x) {
 ...
}

Is that a legal way to force compile time arguments and compile-time evaluation?

 / Jonas

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Gabriel Dos Reis <gdr@cs.tamu.edu>
Date: Wed, 20 May 2009 15:13:46 CST
Raw View
Faisal Vali <faisalv@gmail.com> writes:

| Consider class 'C' which is intended to be a template that results in
| a 'literal type':
>
| template<int N> struct C
| {
|   int n;
|   constexpr C(int n) : n(n) { }
|   constexpr operator int() { return N * n; }
| };
>
| Does any one know if the following code is well-formed?

It is ill-formed.

| (i.e. where is
| the language that supports or forbids these contructs?)
>
| constexpr int foo(const int I)
| {
|   return I < 0 ? C<I>(I + 10) : foo(I - 1);
| }

'I' is not an integral constant expression.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Gabriel Dos Reis <gdr@cs.tamu.edu>
Date: Wed, 20 May 2009 15:13:12 CST
Raw View
Jonas Persson <l.j.persson@gmail.com> writes:

| SG skrev:
>>>
>>> Also, does anyone know where exactly it states when these constexpr
>>> functions get executed?
>>
>> A constexpr is a normal function and can be invoked at runtime. In
>> case a constexpr function definition is well-formed and some specific
>> call to this function uses constant expressions for all arguments this
>> function will be evaluated at compile-time. There's a way to make sure
>> that a specific constexpr function invocation is done at compile-time:
>>
>>   constexpr int foo(int x) {
>>     return 3*x+2;
>>   }
>>
>>   int main() {
>>     constexpr int x = foo(42); // OK, computed at compile-time
>>   }
>
| How about if the function is declared as
|
| constexpr int foo(constexpr int x) {
                     ^^^^^^^^^^^^^^^

invalid.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Gabriel Dos Reis <gdr@cs.tamu.edu>
Date: Wed, 20 May 2009 15:12:48 CST
Raw View
SG <s.gesemann@gmail.com> writes:

| On 18 Mai, 05:48, Faisal Vali <fais...@gmail.com> wrote:
>> Consider class 'C' which is intended to be a template that results in
>> a 'literal type':
>>
>> template<int N> struct C
>> {
>>   int n;
>>   constexpr C(int n) : n(n) { }
>>   constexpr operator int() { return N * n; }
>> };
>>
>> Does any one know if the following code is well-formed? (i.e. where is
>> the language that supports or forbids these contructs?)
>>
>> constexpr int foo(const int I)
>> {
>>   return I < 0 ? C<I>(I + 10) : foo(I - 1);
>> }
>
| This is ill-formed due to a number of reasons:
| 1. The variable 'I' can't be a template argument for C.

Indeed, it is not an integral constant expression.

| 2. If I remember correctly constexpr functions are not allowed to
| recurse.

Now, they can.


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: daniel.kruegler@googlemail.com
Date: Wed, 20 May 2009 15:11:21 CST
Raw View
On 20 Mai, 05:48, Jonas Persson <l.j.pers...@gmail.com> wrote:
> SG skrev:
>
>
>
>
>
> >> Also, does anyone know where exactly it states when these constexpr
> >> functions get executed?
>
> > A constexpr is a normal function and can be invoked at runtime. In
> > case a constexpr function definition is well-formed and some specific
> > call to this function uses constant expressions for all arguments this
> > function will be evaluated at compile-time. There's a way to make sure
> > that a specific constexpr function invocation is done at compile-time:
>
> >   constexpr int foo(int x) {
> >     return 3*x+2;
> >   }
>
> >   int main() {
> >     constexpr int x = foo(42); // OK, computed at compile-time
> >   }
>
> How about if the function is declared as
>
> constexpr int foo(constexpr int x) {
>  ...
>
> }
>
> Is that a legal way to force compile time arguments and compile-time evaluation?

No, it isn't, see [dcl.constexpr]/1:

"[..] [ Note: function parameters cannot be declared constexpr.  end
note ][ Example: [..]
   int next(constexpr int x) { // error
   return x + 1;
} [..] "

HTH & Greetings from Bremen,

Daniel Kr  gler


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Faisal Vali <faisalv@gmail.com>
Date: Sun, 17 May 2009 21:48:39 CST
Raw View
Consider class 'C' which is intended to be a template that results in
a 'literal type':

template<int N> struct C
{
  int n;
  constexpr C(int n) : n(n) { }
  constexpr operator int() { return N * n; }
};

Does any one know if the following code is well-formed? (i.e. where is
the language that supports or forbids these contructs?)

constexpr int foo(const int I)
{
  return I < 0 ? C<I>(I + 10) : foo(I - 1);
}

If the above code is legal, I would expect that each call to foo with
a different integer literal would require the compiler to generate a
new definition of foo (i.e similar to as if function was declared as
template<int I> int foo(), and instantiated as foo<8>() etc.)?

And what about the following? (which brings the templatization-like
issues
to the declarator)

constexpr auto foo2(const int I) -> C<I>
{
  return I < 0 ? C<I>(I + 10) : foo(I - 1);
}


Also, does anyone know where exactly it states when these constexpr
functions get executed?

thanks,
Faisal Vali
Radiation Oncology
Loyola

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]