Last active
April 29, 2019 11:42
-
-
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 ).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note:
nonstd::expected
usesswap()
inoperator=( expected const & other )
.Idem for
-std:c++17
.Ok with: