Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will consteval allow using static_assert on function arguments?

Currently you cannot use static_assert to verify parameters of a constexpr function, even if all calls to it are indeed constexpr. That makes sense because the compiler still has to create a non-constexpr instantiation of this function in case some other module will try to call it. Sadly, this is the case even if the function is static or in an anonymous namespace.

C++20 however, will introduce a new keyword consteval which is like constexpr but it doesn't allow calling a function in a non-constexpr way. In this case, the compiler can know for sure that the function parameters will always be known at compile time. Therefore, in theory it should be possible to validate them with static_assert.

The question is: Does the standard allow it?


Example:

#include <iostream>

consteval char operator""_bchar(const char text[], const size_t length)
{
    static_assert(length == 8, "Binary char has to have 8 digits!"); // <-- This is currently not possible.
    uint8_t byte = 0;
    for (size_t i = 0; i != length; ++i)
    {
        byte <<= 1;
        byte |= text[i] == '1' ? 0b00000001 : 0b00000000;
    }
    return byte;
}

int main()
{
    std::cout << "01000001"_bchar << std::endl;
    return 0;
}

I'm asking because I'm going to write some user-defined literals (more complicated than the example). I have an option to use compiler extensions to deal with the validation or wait a little for the compiler update and write fully standard-compliant code.

like image 445
NO_NAME Avatar asked Jul 26 '19 20:07

NO_NAME


People also ask

What is constant expression in static assert?

The constant-expression parameter of a static_assert declaration represents a software assertion. A software assertion specifies a condition that you expect to be true at a particular point in your program. If the condition is true, the static_assert declaration has no effect.

How to do static assertion since c++ 11 standard?

How to do static assertion since C++ 11 standard? The C++ 11 standard introduced a feature named static_assert () which can be used to test a software assertion at the compile time.

What is the scope of the static assert keyword?

(The static_assert keyword is technically a declaration, even though it does not introduce new name into your program, because it can be used at namespace scope.) In the following example, the static_assert declaration has namespace scope. Because the compiler knows the size of type void *, the expression is evaluated immediately.

What is static assertion failed error?

static_assert (N >= 0, "length of array a is negative."); error: static assertion failed: length of array a is negative. The constant_expression passed in static_assertion needs to be a valid expression.


1 Answers

Will consteval allow to use static_assert on function arguments?

No. Function arguments have never been, and will continue to not be, usable as constant expressions.

There is a difference between something being constant evaluated and being usable as a constant-expression. consteval ensures that we're in a constant evaluation context, but it does not also cause everything to become constant-expressions.

In order to allow function arguments to be usable as constant expressions, you would need to make everything implicitly a template:

template <int> struct X { };

consteval auto foo(int i) {
    static_assert(i > 10); // in order to allow this...
    return X<i>{};         // ... you'd have to allow this too
}

And now foo(20) and foo(30) return different types. That's a template.


Important background reading for understanding why this is a fundamental and inherent limitation can be found in Andrew Sutton's Translation and evaluation: A mental model for compile-time metaprogramming:

Having a mental model of compile-time evaluation that physically separates it from the process of translation has been extremely helpful for me. In particular, it has helped me understand what is not possible (e.g., instantiating a template during evaluation). This helps prune the design space for otherwise large and complex language features. Hopefully, others will find this note helpful as well.


With static_assert specifically though, you can add a workaround just to cause a compilation failure. That's just adding anything at all that can't be used during constant evaluation. Like:

#define CONSTEVAL_STATIC_ASSERT(c, msg) do { if (!(c)) throw msg; } while(false)

as in:

consteval char operator""_bchar(const char text[], const size_t length)
{
    CONSTEVAL_STATIC_ASSERT(length == 8, "Binary char has to have 8 digits!");
    // ...
}
like image 147
Barry Avatar answered Sep 16 '22 14:09

Barry