Always defer evaluation of static_assert to template instantiation time.

489 views
Skip to first unread message

Bengt Gustafsson

unread,
Oct 18, 2018, 9:16:57 PM10/18/18
to ISO C++ Standard - Future Proposals
It seems a recurring pattern that you try to use static_assert(false); in template code to indicate that a template should not be instantiated, but this currently does not work as the assert fires before the template is ever instantiated. A work around I have seen is:

        // Delay evaluation of the assert by making it dependent on a template parameter
 
33
+
        static_assert(sizeof(ExprT) == -1, "Conversion between these types is not supported");

It seems to me that it would be a reasonable change to not let a static_assert(false) fire in template code unless the template is actually instantiated.

Are there any show-stoppers preventing such a change?

Nicolas Lesser

unread,
Oct 19, 2018, 10:21:04 AM10/19/18
to std-pr...@isocpp.org
The problem with this is that it would special case the condition of staric_assert.

If the condition in a template is not value-dependent, and it evaluates to false, then the program is ill-formed. [temp.res]p8


IMO the right solution would be to not use such a static_assert. You can always delete an overload, make an incomplete type, ... if you don't want people using that particular instantiation.

--
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-proposal...@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/1bc49018-90f2-47e4-ad3b-ed657c39d8cc%40isocpp.org.

Bengt Gustafsson

unread,
Oct 19, 2018, 11:32:10 AM10/19/18
to ISO C++ Standard - Future Proposals
Well, you pointing at the rule I want to change as a motivation for not changing the rule does not lead very far. If I wasn't proposing a change to the language I would not be posting on this list.

There is already special handling of the boolean expression in a static_assert compared to other constexpr boolean expressions: It causes a compilation error if false. It can't be a big deal for a compiler to defer the constexpr execution of this particular boolean expression to template instantiation time if encountered in template code.

The example I gave (not by my hand) is typical of the trickery people employ to avoid this problem, which is ugly and hard to understand.

The ideas you propose as alternatives have the drawback that they don't allow you to affix your own error message (which was the reason to add static_assert in the first place). Also there is no technique that works in all contexts where static_asserts work, so you'd have to think of how to get the effect each time.

Brian Bi

unread,
Oct 19, 2018, 12:05:52 PM10/19/18
to std-pr...@isocpp.org
I think that it would be fine to special-case it, if you can provide a solid rationale. Static assertions are heavy-handed because they bypass SFINAE, and I've almost always found it preferable to avoid unconditional static assertions for this reason. If you are going to submit a paper, be sure to provide some good examples of when having the proposed construct be well-formed would significantly improve the code.

My understanding is that the rule in [temp.res] is intended to prevent the compiler from being forced to tolerate provably nonsensical constructs that appear in a template. As far as I can tell, a static assert with false condition is not something that would make it hard for the compiler to continue, so this is something we could special-case.



--
Brian Bi

Gašper Ažman

unread,
Oct 20, 2018, 7:09:28 AM10/20/18
to std-pr...@isocpp.org
I can confirm I did this a lot in a previous library that I wrote.

It's a common pattern where you want to tell the user that what they are trying to do will lead to wrong code, so you actually make a template that matches better in the you-used-it-wrong case and gives a friendly error (static-assert) message, instead of SFINAE-ing out and giving 48k of a template dump that no non-expert can parse into "oh, I should have tried to call this with a non-const object.".

You can quote me if you write this paper. I'm all for it. There are no cases where I don't want to defer static_assert(false) in a template definition to instantiation time.

pa...@lib.hu

unread,
Oct 20, 2018, 8:49:33 AM10/20/18
to ISO C++ Standard - Future Proposals
I completely agree with the motivation and the shown example looks like another embarrassment.

Yes, it is just another entry on the list of victims from the export-detour, but I think it stands out enough to be addressed as "special case" until a better general way to force full instantiation-time substitution emerges.

Is there a motivation to have a 1st phase static_assert evaluation in a template?  Maybe inside an if constexpr block.

As for specification, we already have like 4 pages describing what is dependent in the template, adding one line for static_assert fells like a drop in the ocean. Maybe can just use the value-dependent expression section to state the condition part of static_assert is always such.  Then all the rest just falls in place.

inkwizyt...@gmail.com

unread,
Oct 20, 2018, 7:02:30 PM10/20/18
to ISO C++ Standard - Future Proposals


On Saturday, October 20, 2018 at 1:09:28 PM UTC+2, Gašper Ažman wrote:
I can confirm I did this a lot in a previous library that I wrote.

It's a common pattern where you want to tell the user that what they are trying to do will lead to wrong code, so you actually make a template that matches better in the you-used-it-wrong case and gives a friendly error (static-assert) message, instead of SFINAE-ing out and giving 48k of a template dump that no non-expert can parse into "oh, I should have tried to call this with a non-const object.".

You can quote me if you write this paper. I'm all for it. There are no cases where I don't want to defer static_assert(false) in a template definition to instantiation time.

On Fri, Oct 19, 2018 at 5:05 PM Brian Bi <bbi...@gmail.com> wrote:
I think that it would be fine to special-case it, if you can provide a solid rationale. Static assertions are heavy-handed because they bypass SFINAE, and I've almost always found it preferable to avoid unconditional static assertions for this reason. If you are going to submit a paper, be sure to provide some good examples of when having the proposed construct be well-formed would significantly improve the code.

My understanding is that the rule in [temp.res] is intended to prevent the compiler from being forced to tolerate provably nonsensical constructs that appear in a template. As far as I can tell, a static assert with false condition is not something that would make it hard for the compiler to continue, so this is something we could special-case.

On Fri, Oct 19, 2018 at 10:32 AM Bengt Gustafsson <bengt.gu...@beamways.com> wrote:
Well, you pointing at the rule I want to change as a motivation for not changing the rule does not lead very far. If I wasn't proposing a change to the language I would not be posting on this list.

There is already special handling of the boolean expression in a static_assert compared to other constexpr boolean expressions: It causes a compilation error if false. It can't be a big deal for a compiler to defer the constexpr execution of this particular boolean expression to template instantiation time if encountered in template code.

The example I gave (not by my hand) is typical of the trickery people employ to avoid this problem, which is ugly and hard to understand.

The ideas you propose as alternatives have the drawback that they don't allow you to affix your own error message (which was the reason to add static_assert in the first place). Also there is no technique that works in all contexts where static_asserts work, so you'd have to think of how to get the effect each time.

I wondering why in first place we have current behavior? What is use case where this is useful?
One place I could image is where you write unintendly code that can't compile because you mix up condition but in 95% cases is impossible to catch because it depend on template parameter.
Overall for me I would prefer to change this to proposed behavior that assertions are only trigger when template is used, this is similar do how `assert(false)` work, even compiler see that is impossible to fulfill but it break only when code try execute it.

Reply all
Reply to author
Forward
0 new messages