constexpr by default?

221 views
Skip to first unread message

Barry Revzin

unread,
Jun 26, 2017, 1:47:45 PM6/26/17
to ISO C++ Standard - Future Proposals
Over the last few years, we've had this large proliferation of constexpr functions - especially after C++14 relaxed what was allowed to be constexpr. Now we're in this state where basically any type that is literal just has all of its member functions marked constexpr. This ends up being really... weird. std::string_view for instance has member functions like:

constexpr void remove_prefix(size_type );
constexpr void swap(basic_string_view& ) noexcept;

These seem fundamentally... odd. constexpr looks a lot like const so my first reaction is always "well, how can you possibly swap constexpr? How does constexpr void make sense?" But then, constexpr is there because it has to be to used in a constexpr function. It doesn't really provide any meaning. It doesn't change what the function does or how it works, it's just a toggle that makes it suddenly allowed. We just end up with this constexpr creep where we just have to annotate all the things... Because... reasons. 

In a C++17 world, what are those reasons actually? Should we just have constexpr by default? Can we? 

Daniel Krügler

unread,
Jun 26, 2017, 1:52:53 PM6/26/17
to std-pr...@isocpp.org
Two thoughts:

1) How do I opt out, if it becomes the default?
2) What about constexpr as constant initialization constructor?

Thanks,

- Daniel

Jonathan Müller

unread,
Jun 26, 2017, 2:19:07 PM6/26/17
to std-pr...@isocpp.org
On 26.06.2017 19:52, Daniel Krügler wrote:
> Two thoughts:
>
> 1) How do I opt out, if it becomes the default?

Why would you want to opt out?

Just write a function as normal. If it can be constexpr, good. Otherwise
it won't be constexpr.

> 2) What about constexpr as constant initialization constructor?

You mean on variables?
Constructor can be auto constexpr as well.

Daniel Krügler

unread,
Jun 26, 2017, 2:26:27 PM6/26/17
to std-pr...@isocpp.org
2017-06-26 20:19 GMT+02:00 Jonathan Müller <jonathanm...@gmail.com>:
> On 26.06.2017 19:52, Daniel Krügler wrote:
>>
>> Two thoughts:
>>
>> 1) How do I opt out, if it becomes the default?
>
>
> Why would you want to opt out?
>
> Just write a function as normal. If it can be constexpr, good. Otherwise it
> won't be constexpr.

That is not sufficient, because according to the current situation a
program can be ill-formed, if a function is marked as constexpr and
some other condition applies. This applies to main() but also to
[dcl.constexpr] p5, just as examples. What I'm trying to say here is:
This is not just as simple as "Just let's make it the default".

-Daniel

René Eng

unread,
Jun 26, 2017, 2:34:24 PM6/26/17
to std-pr...@isocpp.org

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAGNvRgAB1W7954%2B%2B4sJ1FWN_CPgi4aJrSKPSnEomUFZaz2B0GA%40mail.gmail.com.


Especially regarding the class string_view:
How about a class could be declared as 'constexpr', thereby automatically declaring all its members, functions as well as variables, as 'constexpr'?

-René

--

“Dubito ergo cogito; cogito ergo sum.
(I doubt, therefore I think; I think therefore I am)”
René Descartes

d25f...@outlook.com

unread,
Jun 26, 2017, 2:39:17 PM6/26/17
to std-pr...@isocpp.org

> 在 2017年6月27日,02:19,Jonathan Müller <jonathanm...@gmail.com> 写道:
>
> On 26.06.2017 19:52, Daniel Krügler wrote:
>> Two thoughts:
>> 1) How do I opt out, if it becomes the default?
>
> Why would you want to opt out?
>
> Just write a function as normal. If it can be constexpr, good. Otherwise it won't be constexpr.

Then how can I be sure the function [is meant to be] used in a constant expression? By
'is meant to be' I mean, the author promised the function will keep its constexpr-ness
in the future, that is, the constexpr-ness was not by accident.

By make everything constexpr by default without a way to opt out, either:

1) the caller accept the fact that every function he called in constant expression may
stop being constexpr some day, and break his code, or
2) every function that was not initially constexpr have to keep being constexpr since
then.

Ray Hamel

unread,
Jun 26, 2017, 3:04:22 PM6/26/17
to ISO C++ Standard - Future Proposals
What about a constexpr expression that would, if possible, recursively force evaluation of all contained function calls as constant expressions, and generate a compile-time error if that isn't possible?

constexpr size_t foo = constexpr(strlen("bar")); // 3, or error

This would make any assumptions the caller is making about constexpr-eligiblity explicit.

What would really be helpful, IMO, is a way to provide both constexpr and non-constexpr overloads. Although I could see the argument that the negatives of the perceived increase in boilerplate outweigh the positives for metaprogramming.

Sean Middleditch

unread,
Jun 26, 2017, 3:28:59 PM6/26/17
to ISO C++ Standard - Future Proposals
On Monday, June 26, 2017 at 12:04:22 PM UTC-7, Ray Hamel wrote:
What about a constexpr expression that would, if possible, recursively force evaluation of all contained function calls as constant expressions, and generate a compile-time error if that isn't possible?


A very primary problem is that one would want the errors for a function intended to be constexpr to be raised at the time of semantic analysis of that function itself, not only at call sites.

If a function is meant to be constexpr it _should_ have required markup to inform both the user and the compiler _at that point in the code_ that the function must adhere to the rules of constexpr functions.

The problems with needing to mark up tons of member functions of a constant type are imo indeed better solved by just being able to set a whole class as constexpr, though of course rules are necessary to support constexpr types with non-constexpr member functions / constructors (e.g. rules that constexpr classes have all _eligable_ member functions marked constexpr implicitly, or adding a noconstexpr or constexpr(false) tag to functions, or something silly like that.

I do like the idea of a constexpr() expression - or something like it - to more easily ensure an expression is evaluated at compile time, rather than having to assign the expression to an otherwise unnecessary constexpr temporary.

A good part of your complaint is really just an unfortunate bit of C++ grammer: the constexpr goes next to the return type and not on the function. It'd have been really great for constexpr - and simialr keywords - to all be after the parameter list so we'd get e.g.: int function() constexpr { return blah; } // much more obvious I think, but that ship has sailed

d25f...@outlook.com

unread,
Jun 26, 2017, 4:05:56 PM6/26/17
to std-pr...@isocpp.org

> On 27 Jun 2017, at 03:28, Sean Middleditch <sean.mid...@gmail.com> wrote:
>
> [...]
>
> A good part of your complaint is really just an unfortunate bit of C++ grammer: the constexpr goes next to the return type and not on the function. It'd have been really great for constexpr - and simialr keywords - to all be after the parameter list so we'd get e.g.: int function() constexpr { return blah; } // much more obvious I think, but that ship has sailed

Sorry for getting off the topic but..

IMHO, placing 'constexpr' before the return type makes it a bit clear that only the return value (may) be constant, but nothing else (parameter, for example).

IIRC there have been some discussions / proposals about constexpr parameter in std-discussion / this forum.

btw: It seems to me that the constexpr is still not explicit enough about whether / when a function's return value is constexpr since, even if the function is marked as 'constexpr', it can behave in a non-constexpr way when called with certain parameters if it's implemented that way. e.g.:

constexpr int f(int x) { if (x) throw 1; return x; } // f(1) is not constexpr.

And even if f keeps being 'constexpr', it can behave in a non-constexpr way when called with some different parameters in the future, presumbly without anyone's notice..

Thiago Macieira

unread,
Jun 26, 2017, 4:45:11 PM6/26/17
to std-pr...@isocpp.org
On segunda-feira, 26 de junho de 2017 10:47:45 PDT Barry Revzin wrote:
> Over the last few years, we've had this large proliferation of constexpr
> functions - especially after C++14 relaxed what was allowed to be
> constexpr. Now we're in this state where basically any type that is literal
> just has all of its member functions marked constexpr. This ends up being
> really... weird. std::string_view for instance has member functions like:
>
> constexpr void remove_prefix(size_type );
> constexpr void swap(basic_string_view& ) noexcept;

Don't forget the noexcept repetition:

constexpr void function(...) noexcept(body)
{
body;
}


--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center

Arthur O'Dwyer

unread,
Jun 26, 2017, 6:43:34 PM6/26/17
to ISO C++ Standard - Future Proposals, d25f...@outlook.com
This is a fair point.  But surely the counter-argument is that very few things in C++ work this way today (constexpr, const, and noexcept being the three exceptions I can think of, and all three of them famously leading to tons of boilerplate).

The usual way to handle "documented invariants" or "requirements" of this nature is to annotate them in the source code with either comments or static_asserts:

class MyFoo {
    int one() const;  // I promise this will never stop being callable on a const object
    constexpr int two();  // I promise this will never stop being callable in a constexpr context
    int three() noexcept;  // I promise this will never stop being nothrow
    int four();
};
static_assert(is_trivially_copy_constructible_v<MyFoo>);  // I promise this will never stop being trivially copy-constructible
static_assert(is_aggregate_v<MyFoo>);  // I promise this will never stop being memberwise initializable
static_assert(sizeof(&MyFoo::four));  // I promise this function will never be overloaded
static_assert(is_same_v<decltype(declval<MyFoo&>().four(), int>);  // I promise this return type will never change

and so on and so forth.  If we had the syntax for it, then we could easily annotate our source code with

static_assert(is_constexpr_constructible_v<MyFoo>);  // I promise this will never stop being constexpr constructible
static_assert(constexpr(MyFoo().four()));  // I promise this expression will never stop being evaluable in a constexpr context

Const and noexcept are actually special cases in two related ways: they participate in name-mangling and need to match up across module boundaries. You can declare a function "noexcept" without ever seeing its definition.  But this is not true for constexpr; a function with no visible definition cannot possibly be evaluated at compile time!

(A) The constexpr-ness of a function is part of its API.
(B) If a function is not inline, then it cannot be constexpr.
(C) If a function is inline, then its definition is part of its API.
(QED?): We can let the constexpr-ness of a function be deduced from its definition, without changing what is part of its API.


So yeah, I think that if your client code relies on the constexpr-ness of a function that isn't specifically annotated as such, your code is just as broken as client code that relies on the trivial-ness or nothrow-ness of a function that isn't specifically annotated as such.  But does that mean that we need special language keywords for annotating constexpr-ness, trivial-ness, or nothrow-ness? IMHO perhaps not.

my $.02,
Arthur

Johannes Schaub

unread,
Jun 27, 2017, 2:19:30 AM6/27/17
to std-pr...@isocpp.org
2017-06-26 20:26 GMT+02:00 Daniel Krügler <daniel....@gmail.com>:
Daniel, I'm not convinced of these examples. If the program would be
ill-formed for an implicitly constexpr function, it just won't mark
the function implicitly constexpr. Can you give an example where that
strategy would fail?

Would implicitly marking a function constexpr cost too much resources
on the compiler? I Imagine the compiler would possibly need to keep
more information in the AST for being able to constexpr it. Is that
the reason why you have to explicitly opt-in to it?

Victor Dyachenko

unread,
Jun 27, 2017, 2:38:36 AM6/27/17
to ISO C++ Standard - Future Proposals
Is constexpr mark a guarantee that function can be evaluated in compile time? How about the story with constexpr string_view(const char * )?

https://developercommunity.visualstudio.com/content/problem/24487/constexpr-stdstring-view-from-string-literal.html

Daniel Krügler

unread,
Jun 27, 2017, 2:40:36 AM6/27/17
to std-pr...@isocpp.org
2017-06-27 8:19 GMT+02:00 'Johannes Schaub' via ISO C++ Standard -
Future Proposals <std-pr...@isocpp.org>:
> Daniel, I'm not convinced of these examples. If the program would be
> ill-formed for an implicitly constexpr function, it just won't mark
> the function implicitly constexpr. Can you give an example where that
> strategy would fail?

I'm merely criticizing the seemingly simple idea of changing the
default, because it overlooks the complexity details of the current
rules and I'm not able to understand the full consequences without
seeing the full proposal. And given that there is still strong
resistance against accepting

http://cplusplus.github.io/LWG/lwg-active.html#2892

I expect that to become a controversial request, but it surely depends
on the actual content of a corresponding proposal.

- Daniel

Victor Dyachenko

unread,
Jun 27, 2017, 10:19:16 AM6/27/17
to ISO C++ Standard - Future Proposals
Have you already seen this?
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0639r0.html

Standard Library containers miss constexpr
  • Solution: It is simple to add constexpr all around the container declaration

Daniel Krügler

unread,
Jun 27, 2017, 2:27:00 PM6/27/17
to std-pr...@isocpp.org
Yes, I have read the paper, but that paper alone is neither a proof of
the OP's suggestion to work in all cases nor does the paper suggest
this approach. It is a very nice work, though.

- Daniel
Reply all
Reply to author
Forward
0 new messages