Skip to content

Instantly share code, notes, and snippets.

@martinmoene
Last active April 29, 2019 11:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save martinmoene/9936d274ea6b31913d771f60da4218af to your computer and use it in GitHub Desktop.
Save martinmoene/9936d274ea6b31913d771f60da4218af to your computer and use it in GitHub Desktop.
Jinja2Cpp: ParseError and assignment/swap -- Note: nonstd::expected uses swap() in operator=( expected const & other ).
//
// 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
@martinmoene
Copy link
Author

Note: nonstd::expected uses swap() in operator=( expected const & other ).

prompt> cl -std:c++14 -EHsc -c Jina2Cpp-ParseError.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.16.27030.1 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

Jina2Cpp-ParseError.cpp
Jina2Cpp-ParseError.cpp(141): error C2338: std17::is_nothrow_swappable<ParseError>::value

Idem for -std:c++17.

Ok with:

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment