public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* constexpr question
@ 2011-06-09 14:37 Andy Gibbs
  2011-06-09 15:08 ` Jonathan Wakely
  0 siblings, 1 reply; 6+ messages in thread
From: Andy Gibbs @ 2011-06-09 14:37 UTC (permalink / raw)
  To: gcc-help

Hi,

I've been playing around with constexpr in gcc 4.6 and have a question:

This works:

template <int v> struct wrapper
    { enum : int { value = v }; };

constexpr int test1(int a)
    { return a; }

constexpr int test2(int a)
    { return test1(a); }

constexpr int one = 12;
constexpr int two = wrapper<test2(one)>::value;


But this doesn't work:

constexpr int test3(int a)
    { return wrapper<test1(a)>::value; }

constexpr int three = test3(one);


The compiler error is:

In function 'constexpr int test3(int)':
error: 'a' is not a constant expression
note: in template argument for type 'int'


The question I have is: why doesn't (or can't) the second case work?  In
function 'test2' the compiler believes 'a' is a constant expression and the
declaration of variable 'two' shows 'wrapper' can take a constexpr as its
template parameter, so is it just an oversight of the compiler that 'test3'
doesn't compile?  Or is it intentional?

I understand that test3 would not compile if passed a non-constexpr
parameter, whereas test2 would compile -- but this is what I would want:
this way I can stop test3 being used except during compile-time.  Or is
there a better way of doing this?

Thanks for any help!

Andy




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: constexpr question
  2011-06-09 14:37 constexpr question Andy Gibbs
@ 2011-06-09 15:08 ` Jonathan Wakely
  2011-06-09 15:27   ` Jonathan Wakely
  2011-06-09 16:24   ` Andy Gibbs
  0 siblings, 2 replies; 6+ messages in thread
From: Jonathan Wakely @ 2011-06-09 15:08 UTC (permalink / raw)
  To: Andy Gibbs; +Cc: gcc-help

On 9 June 2011 12:26, Andy Gibbs wrote:
> Hi,
>
> I've been playing around with constexpr in gcc 4.6 and have a question:
>
> This works:
>
> template <int v> struct wrapper
>   { enum : int { value = v }; };
>
> constexpr int test1(int a)
>   { return a; }
>
> constexpr int test2(int a)
>   { return test1(a); }
>
> constexpr int one = 12;
> constexpr int two = wrapper<test2(one)>::value;
>
>
> But this doesn't work:
>
> constexpr int test3(int a)
>   { return wrapper<test1(a)>::value; }
>
> constexpr int three = test3(one);
>
>
> The compiler error is:
>
> In function 'constexpr int test3(int)':
> error: 'a' is not a constant expression
> note: in template argument for type 'int'
>
>
> The question I have is: why doesn't (or can't) the second case work?  In
> function 'test2' the compiler believes 'a' is a constant expression and the
> declaration of variable 'two' shows 'wrapper' can take a constexpr as its
> template parameter, so is it just an oversight of the compiler that 'test3'
> doesn't compile?  Or is it intentional?

I'm not certain, but I think the compiler's right.  A constexpr
function isn't one which can *only* be a constant expression, it's one
which is potentially a constant-expression when used in the right
context (e.g. given only constants as arguments.)

You can call test1 and test2 with non-constant arguments, and they act
like normal functions. Or you can call them with constants and they
can appear in constant expressions.  test3 cannot be used like a
normal function.

> I understand that test3 would not compile if passed a non-constexpr
> parameter, whereas test2 would compile -- but this is what I would want:
> this way I can stop test3 being used except during compile-time.  Or is
> there a better way of doing this?

Make the int parameter a template parameter, so it has to be known at
compile-time.

template<int A>
  constexpr int test3()
  { return wrapper<test1(A)>::value; }

constexpr int three = test3<one>();

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: constexpr question
  2011-06-09 15:08 ` Jonathan Wakely
@ 2011-06-09 15:27   ` Jonathan Wakely
  2011-06-09 17:49     ` Andy Gibbs
  2011-06-09 16:24   ` Andy Gibbs
  1 sibling, 1 reply; 6+ messages in thread
From: Jonathan Wakely @ 2011-06-09 15:27 UTC (permalink / raw)
  To: Andy Gibbs; +Cc: gcc-help

>> The question I have is: why doesn't (or can't) the second case work?  In
>> function 'test2' the compiler believes 'a' is a constant expression and the

I don't think that's how it works.

In test2 the expression test1(a) is just a normal expression, calling
a function that returns an int. 'a' is not a constant expression in
the body of test2.  In the right context it can be substituted with a
constant expression, but is not actually a constant expression.

In the definition of the constexpr variable 'two' the expression
test(2) is a call to a constexpr function, so "function invocation
substitution" takes place. That substitutes the constant 2 in place of
'a' in the body of test2, producing test1(2), which is also a call to
a constexpr function, so function invocation substitution occurs
again, substituting 2 for 'a' in the body of test1, which produces
'return 2' which is a constant expression.

Similarly, in test3 'a' is not a constant expression (it's just
something which could be substituted for one in the right context) and
so it can't be used in a way which *requires* a constant expression,
such as a template parameter.

Does that help?

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: constexpr question
  2011-06-09 15:08 ` Jonathan Wakely
  2011-06-09 15:27   ` Jonathan Wakely
@ 2011-06-09 16:24   ` Andy Gibbs
  2011-06-09 18:01     ` Jonathan Wakely
  1 sibling, 1 reply; 6+ messages in thread
From: Andy Gibbs @ 2011-06-09 16:24 UTC (permalink / raw)
  To: gcc-help; +Cc: Jonathan Wakely

On Thursday, June 09, 2011 2:52 PM, Jonathan Wakely wrote:

>> The question I have is: why doesn't (or can't) the second case work? In
>> function 'test2' the compiler believes 'a' is a constant expression and 
>> the
>> declaration of variable 'two' shows 'wrapper' can take a constexpr as its
>> template parameter, so is it just an oversight of the compiler that 
>> 'test3'
>> doesn't compile? Or is it intentional?
>
> I'm not certain, but I think the compiler's right.  A constexpr
> function isn't one which can *only* be a constant expression, it's one
> which is potentially a constant-expression when used in the right
> context (e.g. given only constants as arguments.)
>
> You can call test1 and test2 with non-constant arguments, and they act
> like normal functions. Or you can call them with constants and they
> can appear in constant expressions.  test3 cannot be used like a
> normal function.

Jonathan,

Thanks for your reply.  I think that you're right that the compiler is 
probably working according to the logic you have suggested.  Maybe it is a 
overlooked feature in the proposed new standard.  I believe it isn't 
necessarily the case that you'd always want a constexpr function that also 
can be used as a normal (run-time) function since it may implement an 
algorithm suitable (i.e. possible) for compile-time use but unsuitable (i.e. 
inefficient) for run-time use.  The idea, of course, would be to implement 
two different functions, one for use at compile-time, one for use at 
run-time.  The problem for me is how to stop my users using the compile-time 
(i.e. inefficient) function at run-time.  My experience is that 
documentation is often not enough!  If it had worked, my wrapper idea would 
have been perfect: it would have stopped the compile-time function being 
used accidentally at run-time because the parameter wouldn't be constexpr 
and couldn't therefore be a template parameter; and the user would otherwise 
be able to decide whether to use the compile-time or the run-time function 
as he wished.

>> I understand that test3 would not compile if passed a non-constexpr
>> parameter, whereas test2 would compile -- but this is what I would want:
>> this way I can stop test3 being used except during compile-time. Or is
>> there a better way of doing this?
>
> Make the int parameter a template parameter, so it has to be known at
> compile-time.
>
> template<int A>
>   constexpr int test3()
>   { return wrapper<test1(A)>::value; }
>
> constexpr int three = test3<one>();

Yes, this would work, but I'm afraid defeats the aim I'm trying to acheive. 
;o)

Cheers
Andy


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: constexpr question
  2011-06-09 15:27   ` Jonathan Wakely
@ 2011-06-09 17:49     ` Andy Gibbs
  0 siblings, 0 replies; 6+ messages in thread
From: Andy Gibbs @ 2011-06-09 17:49 UTC (permalink / raw)
  To: gcc-help; +Cc: Jonathan Wakely

On Thursday, June 09, 2011 5:08 PM, Jonathan Wakely wrote:

>>> The question I have is: why doesn't (or can't) the second case work? In
>>> function 'test2' the compiler believes 'a' is a constant expression and
>>> the
>
> I don't think that's how it works.
>
> In test2 the expression test1(a) is just a normal expression, calling
> a function that returns an int. 'a' is not a constant expression in
> the body of test2.  In the right context it can be substituted with a
> constant expression, but is not actually a constant expression.
>
> In the definition of the constexpr variable 'two' the expression
> test(2) is a call to a constexpr function, so "function invocation
> substitution" takes place. That substitutes the constant 2 in place of
> 'a' in the body of test2, producing test1(2), which is also a call to
> a constexpr function, so function invocation substitution occurs
> again, substituting 2 for 'a' in the body of test1, which produces
> 'return 2' which is a constant expression.
>
> Similarly, in test3 'a' is not a constant expression (it's just
> something which could be substituted for one in the right context) and
> so it can't be used in a way which *requires* a constant expression,
> such as a template parameter.
>
> Does that help?

Hmm, I hadn't thought about it that way round.  You've given me an idea
though, so I'm going to go off and try something, to see if I can "trick"
the compiler into doing what I want!!

Cheers
Andy


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: constexpr question
  2011-06-09 16:24   ` Andy Gibbs
@ 2011-06-09 18:01     ` Jonathan Wakely
  0 siblings, 0 replies; 6+ messages in thread
From: Jonathan Wakely @ 2011-06-09 18:01 UTC (permalink / raw)
  To: Andy Gibbs; +Cc: gcc-help

On 9 June 2011 16:21, Andy Gibbs wrote:
>
> Thanks for your reply.  I think that you're right that the compiler is
> probably working according to the logic you have suggested.  Maybe it is a
> overlooked feature in the proposed new standard.  I believe it isn't
> necessarily the case that you'd always want a constexpr function that also
> can be used as a normal (run-time) function since it may implement an
> algorithm suitable (i.e. possible) for compile-time use but unsuitable (i.e.
> inefficient) for run-time use.  The idea, of course, would be to implement
> two different functions, one for use at compile-time, one for use at
> run-time.  The problem for me is how to stop my users using the compile-time
> (i.e. inefficient) function at run-time.  My experience is that
> documentation is often not enough!  If it had worked, my wrapper idea would
> have been perfect: it would have stopped the compile-time function being
> used accidentally at run-time because the parameter wouldn't be constexpr
> and couldn't therefore be a template parameter; and the user would otherwise
> be able to decide whether to use the compile-time or the run-time function
> as he wished.

I don't think it's overlooked feature, I think the current behaviour
is by design.

[dcl.constexpr] p7 says it quite clearly:
A call to a constexpr function produces the same result as a call to
an equivalent non-constexpr function in all respects except that a
call to a constexpr function can appear in a constant expression.

N.B. _can_ appear in a constant expression. It must be a valid C++
function in all other respects, it is just possible to use in places
that didn't allow function calls previously.

A note on p1 says "Function parameters cannot be declared constexpr"
which precludes 'a' being a constant expression (it can only be
substituted by one during function invocation substitution, which only
occurs in the context of constant expressions.)

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2011-06-09 16:24 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-06-09 14:37 constexpr question Andy Gibbs
2011-06-09 15:08 ` Jonathan Wakely
2011-06-09 15:27   ` Jonathan Wakely
2011-06-09 17:49     ` Andy Gibbs
2011-06-09 16:24   ` Andy Gibbs
2011-06-09 18:01     ` Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).