Skip to content

Instantly share code, notes, and snippets.

@martinmoene
Last active April 29, 2019 11:42
Show Gist options
  • Select an option

  • Save martinmoene/9936d274ea6b31913d771f60da4218af to your computer and use it in GitHub Desktop.

Select an option

Save martinmoene/9936d274ea6b31913d771f60da4218af to your computer and use it in GitHub Desktop.

Revisions

  1. martinmoene revised this gist Apr 29, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Jinja2Cpp-ParseError.cpp
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    //
    //
    // If you write
    // ParseError(ParseError&& other) noexcept(true) = default;
    // the type won't be treated as nothrow move-constructable.
  2. martinmoene revised this gist Apr 29, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Jinja2Cpp-ParseError.cpp
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    //
    //
    // If you write
    // ParseError(ParseError&& other) noexcept(true) = default;
    // the type won't be treated as nothrow move-constructable.
  3. martinmoene renamed this gist Apr 29, 2019. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  4. martinmoene renamed this gist Apr 29, 2019. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  5. martinmoene created this gist Apr 29, 2019.
    145 changes: 145 additions & 0 deletions Jinja2Cpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,145 @@
    //
    // If you write
    // ParseError(ParseError&& other) noexcept(true) = default;
    // the type won't be treated as nothrow move-constructable.
    // But if you write this ctor manually - everything is ok.

    #include <initializer_list>
    #include <utility>
    #include <vector>

    struct Token{};
    struct ErrorCode{};
    ;

    struct ParseError
    {
    ParseError() = default;

    ParseError( ErrorCode code, Token tok )
    : errorCode( code )
    , errorToken( tok )
    {}

    ParseError( ErrorCode code, Token tok, std::initializer_list<Token> toks )
    : errorCode( code )
    , errorToken( tok )
    , relatedTokens( toks )
    {}

    ParseError( const ParseError& ) = default;

    #if 1
    ParseError( ParseError&& other ) noexcept(true) = default;
    #else
    ParseError( ParseError&& other ) noexcept
    : errorCode( std::move( other.errorCode ) )
    , errorToken( std::move( other.errorToken ) )
    , relatedTokens( std::move( other.relatedTokens ) )
    {}
    #endif

    ErrorCode errorCode;
    Token errorToken;
    std::vector<Token> relatedTokens;
    };

    #include <type_traits>

    // C++ language version detection (C++20 is speculative):
    // Note: VC14.0/1900 (VS2015) lacks too much from C++14.

    #ifndef nsel_CPLUSPLUS
    # if defined(_MSVC_LANG ) && !defined(__clang__)
    # define nsel_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG )
    # else
    # define nsel_CPLUSPLUS __cplusplus
    # endif
    #endif

    #define nsel_CPP98_OR_GREATER ( nsel_CPLUSPLUS >= 199711L )
    #define nsel_CPP11_OR_GREATER ( nsel_CPLUSPLUS >= 201103L )
    #define nsel_CPP14_OR_GREATER ( nsel_CPLUSPLUS >= 201402L )
    #define nsel_CPP17_OR_GREATER ( nsel_CPLUSPLUS >= 201703L )
    #define nsel_CPP20_OR_GREATER ( nsel_CPLUSPLUS >= 202000L )

    // type traits C++17:

    namespace std17 {

    #if nsel_CPP17_OR_GREATER

    using std::conjunction;
    using std::is_swappable;
    using std::is_nothrow_swappable;

    #else // nsel_CPP17_OR_GREATER

    namespace detail {

    using std::swap;

    struct is_swappable
    {
    template< typename T, typename = decltype( swap( std::declval<T&>(), std::declval<T&>() ) ) >
    static std::true_type test( int );

    template< typename >
    static std::false_type test(...);
    };

    struct is_nothrow_swappable
    {
    // wrap noexcept(epr) in separate function as work-around for VC140 (VS2015):

    template< typename T >
    static constexpr bool test()
    {
    return noexcept( swap( std::declval<T&>(), std::declval<T&>() ) );
    }

    template< typename T >
    static auto test( int ) -> std::integral_constant<bool, test<T>()>{}

    template< typename >
    static std::false_type test(...);
    };

    } // namespace detail

    // is [nothow] swappable:

    template< typename T >
    struct is_swappable : decltype( detail::is_swappable::test<T>(0) ){};

    template< typename T >
    struct is_nothrow_swappable : decltype( detail::is_nothrow_swappable::test<T>(0) ){};

    // conjunction:

    template< typename... > struct conjunction : std::true_type{};
    template< typename B1 > struct conjunction<B1> : B1{};

    template< typename B1, typename... Bn >
    struct conjunction<B1, Bn...> : std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type{};

    #endif // nsel_CPP17_OR_GREATER

    } // namespace std17


    #if 0
    void swap(ParseError &, ParseError &) noexcept;
    #endif

    #define STATIC_ASSERT(expr) \
    static_assert( expr, #expr )

    int main()
    {
    STATIC_ASSERT( std::is_nothrow_move_constructible<ParseError>::value );
    STATIC_ASSERT( std17::is_nothrow_swappable<ParseError>::value );
    }

    // cl -std:c++17 -EHsc -c effe.cpp
    // cl -std:c++14 -EHsc -c effe.cpp