C ++ 20 on the way! Meeting at Rapperswil-Yona

    In early June, the meeting of the WG21 international working group on C ++ standardization ended in the city of Rapperswil-Yona.

    Here is what awaits you under the cut:
    • Contracts and Friends
    • Concepts (without friends)
    • __has_cpp_attribute (unlikely)
    • bit_cast <my_stuff> (some_array)
    • contains , shift_left , shift_right , ispow2 , ceil2 ... and the old algorithms under the new sauce
    • atomic_ref
    • What new can be written in the templates and how it is useful
    • constexpr virtual foo ()
    • Parallelism 2, Reflection and Executors TS

    There will also be a bonus: a mini section for experts:

    • user-declared virtual destructor does not affect the type triviality
    • Where you can shove an exclamation mark and how it can be useful
    • constexpr std :: regex mail_regex (R "((?: (?: [^ <> () \ [\].,;: \ s @ \"] + (?: \. [^ <> () \ [ \].,;: \ s @ \ "] +) *) | \". + \ ") @ (?: (?: [^ <> () \ [\].,;: \ s @ \" ] + \.) + [^ <> () \ [\].,;: \ s @ \ "] {2,}))")


    Contracts


    In C ++, 20 have accepted contracts. So, you can soon forget about using macros for asserts, get the best documentation out of the box and even notice the performance gain. Contracts look like in practice:

    std::stringget_name_by_login(std::string_view login)
        [[expects: !login.empty() ]]
        [[ensures ret_value: !ret_value.empty() ]]
    ;
    

    In the description above, everything in double brackets is a contract. So, from them:

    • The compiler (depending on the compilation flags) will generate assertions.
    • The compiler (depending on the compilation flags) will be able to draw conclusions and optimize the code based on them. For example, it will be able to completely remove the check for the voidness of the return value in the user code.
    • A third-party utility (for example, doxygen) will be able to generate more complete documentation in the function without the need to explicitly pre-post / post conditions.
    • Static analyzers will be able to analyze the code and find situations where the precondition is guaranteed to be violated (yes, without any runtime tests).

    Contract details are available in official paper .

    The library from FG21 and Fails is in a hurry to help the contracts , which allows to save and print the glass trace. So you can set the handler of the failed contract and print in it a sequence of calls that led to the problem:

    void(conststd::contract_violation & e) noexcept {
        std::cerr << "Contract violated in function " << e.function_name() << '\n'
            << std::stacktrace();
    }
    


    In case of breach of contract, we will see a similar message:

    Contract violated infunction std::array<T, N>::operator[](size_type) [with T = int; long unsigned int N = 5ul; ]': 0# std::array<int, 5ul>::operator[](unsigned long) at /usr/include/c++/array:1241# bar(int) at ../example/assert_handler.cpp:172# foo(int) at ../example/assert_handler.cpp:253# main at ../example/assert_handler.cpp:544# 0x00007F991FD69F45in /lib/x86_64-linux-gnu/libc.so.65# 0x0000000000401139
    }
    

    std :: stacktrace has not yet been adopted in C ++ 20, but has passed a design review in the LEWG group, and there is only work to bring its description into line with the rules of the standard in the LWG group. The latest specification is available by reference .

    Concepts


    Concepts as a language feature were already taken at the last meeting of the committee , and this time the main concepts from Ranges TS were accepted into the standard library. So now you can use ready-made concepts to describe the compile-time requirements for template parameters and not worry about writing your own:

    template <classF>
        requiresInvocable<F>
    voidmy_executor::execute(F f) noexcept {
        lock_guard l{data_mutex_};
        push(std::move(f));
    }
    

    A complete list of concepts and their descriptions are available in this proposal .

    Feature-test macros


    For a long time, compilers and standard libraries provide macros to describe the capabilities of the compiler. Now these macros are officially part of the standard and have even been expanded. So it will be possible to check the support of the unlikely attribute by the compiler using the expression __has_cpp_attribute (unlikely) .

    A list of macros taken at the meeting is available in paper .

    bit_cast


    Using reinterpret_cast to convert one trivially copied type to another is a very bad idea. But the temptation is great, and many developers do it. Therefore, the C ++ committee made a function specifically for such cases.

    Easy to use, just replace.

     my_type my = reinterpret_cast<my_type&>(some_array); 
    on
    my_type my = std::bit_cast<my_type>(some_array); 

    Now, if the dimensions of some_array and my_type do not match, or if you are trying to convert nontrivially copied types, you will receive an error message at the compilation stage. In other cases, you will avoid all the terrible errors associated with type aliasing.

    Algorithms and new features


    Here are some useful things added to the standard C ++ 20 library:

    • shift_left (it_begin, it_end, unsigned n) - shifts values ​​in the range to the left by n, as if they called * it_begin = std :: move (* (it_begin + n)), * (it_begin + 1) = std :: move ( * (it_begin + n + 1)) ...
    • shift_right (it_begin, it_end, unsigned n) is similar to the algorithm above, but moves the range right, as if they called * (it_begin + n) = std :: move (* it_begin), * (it_begin + n + 1) = std: : move (* (it_begin + 1)) ...
    • ispow2 (x) - returns true if a number is passed to it, which is a power of two
    • ceil2 (x) - rounds a number up to the nearest number, which is a power of two
    • contains - all associative containers acquired by the function bool contains (const key & v) , which returns true if the key is contained in the container

    In addition, existing algorithms using std :: swap and std :: swap itself have become constexpr . So now you can sort, call std :: nth_element and get their results at the compilation stage. All details are available in paper from WG21.

    atomic_ref


    You work with data structures mainly from one stream, but at some point you need to work with the field atomically? For these cases, the atomic_ref <T> template class has been added (a formal description is available in paper ).

    It should be remembered that atomicity is guaranteed only for operations performed through instances of the atomic_ref <T> classes . So if you write to one variable in a variable without atomic_ref , and you read in another stream through atomic_ref , then in the end nothing good will come out.

    By the way, if you don’t like inconsistent type names (string _view , atomic _ref ), then express your dissatisfaction at the link. If there are enough votes, we will try to bring all the names into one form.

    Class Instances as Template Parameters


    If you wrote class X , and you wrote an operator <=> for it of the following form:

    structX {// ...std::strong_equality operator<=>(const X&, const X&) = default;
        // ...
    };
    

    Then your class can be used as a template parameter:

    template <X x>
    structx_as_template_param {// ...
    };
    

    However, the committee still has a lot of work to modernize the standard library and transfer its various parts to the use of operator <=> .

    constexpr virtual


    Restrictions for functions performed at compile time were relaxed and now you can write classes with constexpr virtual functions.

    Moreover, if in the base class you have the method constexpr virtual int foo (); , then the successor int foo () can be either constexpr or not. When you call foo () at compile time, the compiler will not let you compile the program if you try to perform a non-constexpr virtual function.

    This change, for example, opens the door to implement std :: type_info , which is applicable at compile time , which will allow this class to get Boost.TypeIndex functionality ., with the possibility of guaranteed compile-time work with types:

    template <classT, classU>
    constexprboolis_same() {constexprbool res = (typeid(T) == typeid(U));
        return res;
    }
    

    Latest details are available in paper .

    Parallelism 2, Reflection and Executors TS


    Parallelism 2 is still preparing for the release, details and cool features can be viewed in the last post . Since its publication, the type traits related to simd and the functionality added for vector instructions have been slightly corrected.

    Reflection is being prepared for release as a technical specification (TS). In it, reflection is still done through mechanisms similar to <type_traits> . Plans to bring to the core of the language more functionality for constexpr computing and redo the reflection on constexpr! functions (see below).

    Executors in C ++ 20 are not likely to fall, but will be released as a separate TS. It is possible that their entire design will be revised and simplified.

    user-declared virtual destructor and type triviality


    The change that should get into C ++ 20 (at the next meeting) will affect the performance of various parts of the standard library and compiler optimization, but it is unlikely to be noticeable in daily development:

    structi_am_trivial {int foo;
        char bar;
        virtual ~i_am_trivial() = default;
    };
    

    The idea is that if the destructor is virtual, it does not mean that it is not trivial. So the standard library will be able to understand that the type with which it works, although it has a virtual destructor, does not actually require calling the destructor to release resources. This can give a performance boost, for example, for std :: vector <Base> , where Base has such a virtual destructor.

    constexpr!


    Another interesting change that is being considered for reception in C ++ 20 is constexpr! functions.

    Such functions must be executed only at the compilation stage; any attempt to use them at runtime will result in a compilation error. This is one of the changes needed for reflection in C ++.

    Extra bonus constexpr! functions is their efficient use of compiler resources. Because constexpr!functions are not executed at runtime; the compiler should not generate an intermediate representation (machine instructions) for them and should not keep their memory or optimize them. This dramatically reduces the amount of RAM required by the compiler and speeds up the compilation somewhat. It should have a tangible effect on modern libraries that rely heavily on metaprogramming, like Boost.Hana or [Boost.] PFR .

    Instead of totals: constexpr std :: regex


    Many programming languages ​​are currently compiling / translating regular expressions before the program starts. Thus, when the program starts, all regular expressions are already converted to a optimized finite state machine.

    In C ++, this is not the case:

    boolis_valid_mail(std::string_view mail){
        staticconststd::regex mail_regex(R"((?:(?:[^<>()\[\].,;:\s@\"]+(?:\.[^<>()\[\].,;:\s@\"]+)*)|\".+\")@(?:(?:[^<>()\[\].,;:\s@\"]+\.)+[^<>()\[\].,;:\s@\"]{2,}))");
        returnstd::regex_match(
            std::cbegin(mail),
            std::cend(mail),
            mail_regex
        );
    }
    

    In the above code, the state machine from the regular expression will be built upon the first call to the is_valid_mail () function . This is a long operation, which in addition will be performed in the critical section.

    With upcoming innovations for constexpr calculations (constexpr new, is_constexpr_evaluated (), etc.) it will be possible to do many things in C ++ at the compilation stage, including constexpr std :: regex .

    With constexpr std :: regex, the state machine for the is_valid_mail () function is built at the compilation stage. Moreover, GCC will be able to generate optimized regulars at compile time without static const , since starting with gcc-6 if constexprthe functions all parameters to the input are constants; GCC forces the computation at the compilation stage.

    So, how do you get the idea to make constexpr std :: regex ?

    PS: For those who want money, C ++ practice has recently been Yandex.Taxi Coding Fest . It will be possible to arm and defeat rivals using C ++ 17.

    Also popular now: