Merge pull request #44 from pah/feature/memberiterator
Add explicit MemberIterator, return MemberEnd() from FindMember()
This commit is contained in:
commit
28294fa754
@ -44,8 +44,8 @@ int main(int, char*[]) {
|
|||||||
printf("hello = %s\n", document["hello"].GetString());
|
printf("hello = %s\n", document["hello"].GetString());
|
||||||
|
|
||||||
// Since version 0.2, you can use single lookup to check the existing of member and its value:
|
// Since version 0.2, you can use single lookup to check the existing of member and its value:
|
||||||
Value::Member* hello = document.FindMember("hello");
|
Value::MemberIterator hello = document.FindMember("hello");
|
||||||
assert(hello != 0);
|
assert(hello != document.MemberEnd());
|
||||||
assert(hello->value.IsString());
|
assert(hello->value.IsString());
|
||||||
assert(strcmp("world", hello->value.GetString()) == 0);
|
assert(strcmp("world", hello->value.GetString()) == 0);
|
||||||
(void)hello;
|
(void)hello;
|
||||||
|
@ -15,13 +15,18 @@
|
|||||||
#pragma GCC diagnostic ignored "-Weffc++"
|
#pragma GCC diagnostic ignored "-Weffc++"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
|
||||||
|
#include "internal/meta.h"
|
||||||
|
#include <iterator> // std::iterator, std::random_access_iterator_tag
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace rapidjson {
|
namespace rapidjson {
|
||||||
|
|
||||||
// Forward declaration.
|
// Forward declaration.
|
||||||
template <typename Encoding, typename Allocator>
|
template <typename Encoding, typename Allocator>
|
||||||
class GenericValue;
|
class GenericValue;
|
||||||
|
|
||||||
//! Name-value pair in an object.
|
//! Name-value pair in a JSON object value.
|
||||||
/*!
|
/*!
|
||||||
This class was internal to GenericValue. It used to be a inner struct.
|
This class was internal to GenericValue. It used to be a inner struct.
|
||||||
But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct.
|
But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct.
|
||||||
@ -33,6 +38,144 @@ struct GenericMember {
|
|||||||
GenericValue<Encoding, Allocator> value; //!< value of member.
|
GenericValue<Encoding, Allocator> value; //!< value of member.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
|
||||||
|
|
||||||
|
//! (Constant) member iterator for a JSON object value
|
||||||
|
/*!
|
||||||
|
\tparam Const Is this a constant iterator?
|
||||||
|
\tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document)
|
||||||
|
\tparam Allocator Allocator type for allocating memory of object, array and string.
|
||||||
|
|
||||||
|
This class implements a Random Access Iterator for GenericMember elements
|
||||||
|
of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements].
|
||||||
|
|
||||||
|
\note This iterator implementation is mainly intended to avoid implicit
|
||||||
|
conversions from iterator values to \c NULL,
|
||||||
|
e.g. from GenericValue::FindMember.
|
||||||
|
|
||||||
|
\note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a
|
||||||
|
pointer-based implementation, if your platform doesn't provide
|
||||||
|
the C++ <iterator> header.
|
||||||
|
|
||||||
|
\see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator
|
||||||
|
*/
|
||||||
|
template <bool Const, typename Encoding, typename Allocator>
|
||||||
|
class GenericMemberIterator
|
||||||
|
: public std::iterator<std::random_access_iterator_tag
|
||||||
|
, typename internal::MaybeAddConst<Const,GenericMember<Encoding,Allocator> >::Type> {
|
||||||
|
|
||||||
|
friend class GenericValue<Encoding,Allocator>;
|
||||||
|
template <bool, typename, typename> friend class GenericMemberIterator;
|
||||||
|
|
||||||
|
typedef GenericMember<Encoding,Allocator> PlainType;
|
||||||
|
typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
|
||||||
|
typedef std::iterator<std::random_access_iterator_tag,ValueType> BaseType;
|
||||||
|
|
||||||
|
public:
|
||||||
|
//! Iterator type itself
|
||||||
|
typedef GenericMemberIterator Type;
|
||||||
|
//! Constant iterator type
|
||||||
|
typedef GenericMemberIterator<true,Encoding,Allocator> ConstType;
|
||||||
|
//! Non-constant iterator type
|
||||||
|
typedef GenericMemberIterator<false,Encoding,Allocator> NonConstType;
|
||||||
|
|
||||||
|
//! Pointer to (const) GenericMember
|
||||||
|
typedef typename BaseType::pointer Pointer;
|
||||||
|
//! Reference to (const) GenericMember
|
||||||
|
typedef typename BaseType::reference Reference;
|
||||||
|
//! Signed integer type (e.g. \c ptrdiff_t)
|
||||||
|
typedef typename BaseType::difference_type DifferenceType;
|
||||||
|
|
||||||
|
//! Default constructor (singular value)
|
||||||
|
/*! Creates an iterator pointing to no element.
|
||||||
|
\note All operations, except for comparisons, are undefined on such values.
|
||||||
|
*/
|
||||||
|
GenericMemberIterator() : ptr_() {}
|
||||||
|
|
||||||
|
//! Iterator conversions to more const
|
||||||
|
/*!
|
||||||
|
\param it (Non-const) iterator to copy from
|
||||||
|
|
||||||
|
Allows the creation of an iterator from another GenericMemberIterator
|
||||||
|
that is "less const". Especially, creating a non-constant iterator
|
||||||
|
from a constant iterator are disabled:
|
||||||
|
\li const -> non-const (not ok)
|
||||||
|
\li const -> const (ok)
|
||||||
|
\li non-const -> const (ok)
|
||||||
|
\li non-const -> non-const (ok)
|
||||||
|
|
||||||
|
\note If the \c Const template parameter is already \c false, this
|
||||||
|
constructor effectively defines a regular copy-constructor.
|
||||||
|
Otherwise, the copy constructor is implicitly defined.
|
||||||
|
*/
|
||||||
|
GenericMemberIterator(const NonConstType & it) : ptr_( it.ptr_ ) {}
|
||||||
|
|
||||||
|
//! @name stepping
|
||||||
|
//@{
|
||||||
|
Type& operator++(){ ++ptr_; return *this; }
|
||||||
|
Type& operator--(){ --ptr_; return *this; }
|
||||||
|
Type operator++(int){ Type old(*this); ++ptr_; return old; }
|
||||||
|
Type operator--(int){ Type old(*this); --ptr_; return old; }
|
||||||
|
//@}
|
||||||
|
|
||||||
|
//! @name increment/decrement
|
||||||
|
//@{
|
||||||
|
Type operator+(DifferenceType n) const { return Type(ptr_+n); }
|
||||||
|
Type operator-(DifferenceType n) const { return Type(ptr_-n); }
|
||||||
|
|
||||||
|
Type& operator+=(DifferenceType n) { ptr_+=n; return *this; }
|
||||||
|
Type& operator-=(DifferenceType n) { ptr_-=n; return *this; }
|
||||||
|
//@}
|
||||||
|
|
||||||
|
//! @name relations
|
||||||
|
//@{
|
||||||
|
bool operator==(Type that) const { return ptr_ == that.ptr_; }
|
||||||
|
bool operator!=(Type that) const { return ptr_ != that.ptr_; }
|
||||||
|
bool operator<=(Type that) const { return ptr_ <= that.ptr_; }
|
||||||
|
bool operator>=(Type that) const { return ptr_ >= that.ptr_; }
|
||||||
|
bool operator< (Type that) const { return ptr_ < that.ptr_; }
|
||||||
|
bool operator> (Type that) const { return ptr_ > that.ptr_; }
|
||||||
|
//@}
|
||||||
|
|
||||||
|
//! @name dereference
|
||||||
|
//@{
|
||||||
|
Reference operator*() const { return *ptr_; }
|
||||||
|
Pointer operator->() const { return ptr_; }
|
||||||
|
Reference operator[](DifferenceType n) const { return ptr_[n]; }
|
||||||
|
//@}
|
||||||
|
|
||||||
|
//! Distance
|
||||||
|
DifferenceType operator-(Type that) const { return ptr_-that.ptr_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
//! Internal constructor from plain pointer
|
||||||
|
explicit GenericMemberIterator(Pointer p) : ptr_(p) {}
|
||||||
|
|
||||||
|
Pointer ptr_; //!< raw pointer
|
||||||
|
};
|
||||||
|
|
||||||
|
#else // RAPIDJSON_NOMEMBERITERATORCLASS
|
||||||
|
|
||||||
|
// class-based member iterator implementation disabled, use plain pointers
|
||||||
|
|
||||||
|
template <bool Const, typename Encoding, typename Allocator>
|
||||||
|
struct GenericMemberIterator;
|
||||||
|
|
||||||
|
//! non-const GenericMemberIterator
|
||||||
|
template <typename Encoding, typename Allocator>
|
||||||
|
struct GenericMemberIterator<false,Encoding,Allocator> {
|
||||||
|
//! use plain pointer as iterator type
|
||||||
|
typedef GenericMember<Encoding,Allocator>* Type;
|
||||||
|
};
|
||||||
|
//! const GenericMemberIterator
|
||||||
|
template <typename Encoding, typename Allocator>
|
||||||
|
struct GenericMemberIterator<true,Encoding,Allocator> {
|
||||||
|
//! use plain const pointer as iterator type
|
||||||
|
typedef const GenericMember<Encoding,Allocator>* Type;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_NOMEMBERITERATORCLASS
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// GenericValue
|
// GenericValue
|
||||||
|
|
||||||
@ -55,8 +198,8 @@ public:
|
|||||||
typedef Encoding EncodingType; //!< Encoding type from template parameter.
|
typedef Encoding EncodingType; //!< Encoding type from template parameter.
|
||||||
typedef Allocator AllocatorType; //!< Allocator type from template parameter.
|
typedef Allocator AllocatorType; //!< Allocator type from template parameter.
|
||||||
typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
|
typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
|
||||||
typedef Member* MemberIterator; //!< Member iterator for iterating in object.
|
typedef typename GenericMemberIterator<false,Encoding,Allocator>::Type MemberIterator; //!< Member iterator for iterating in object.
|
||||||
typedef const Member* ConstMemberIterator; //!< Constant member iterator for iterating in object.
|
typedef typename GenericMemberIterator<true,Encoding,Allocator>::Type ConstMemberIterator; //!< Constant member iterator for iterating in object.
|
||||||
typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array.
|
typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array.
|
||||||
typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array.
|
typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array.
|
||||||
|
|
||||||
@ -276,7 +419,8 @@ public:
|
|||||||
A better approach is to use the now public FindMember().
|
A better approach is to use the now public FindMember().
|
||||||
*/
|
*/
|
||||||
GenericValue& operator[](const Ch* name) {
|
GenericValue& operator[](const Ch* name) {
|
||||||
if (MemberIterator member = FindMember(name))
|
MemberIterator member = FindMember(name);
|
||||||
|
if (member != MemberEnd())
|
||||||
return member->value;
|
return member->value;
|
||||||
else {
|
else {
|
||||||
RAPIDJSON_ASSERT(false); // see above note
|
RAPIDJSON_ASSERT(false); // see above note
|
||||||
@ -289,7 +433,8 @@ public:
|
|||||||
// This version is faster because it does not need a StrLen().
|
// This version is faster because it does not need a StrLen().
|
||||||
// It can also handle string with null character.
|
// It can also handle string with null character.
|
||||||
GenericValue& operator[](const GenericValue& name) {
|
GenericValue& operator[](const GenericValue& name) {
|
||||||
if (Member* member = FindMember(name))
|
MemberIterator member = FindMember(name);
|
||||||
|
if (member != MemberEnd())
|
||||||
return member->value;
|
return member->value;
|
||||||
else {
|
else {
|
||||||
RAPIDJSON_ASSERT(false); // see above note
|
RAPIDJSON_ASSERT(false); // see above note
|
||||||
@ -299,37 +444,51 @@ public:
|
|||||||
}
|
}
|
||||||
const GenericValue& operator[](const GenericValue& name) const { return const_cast<GenericValue&>(*this)[name]; }
|
const GenericValue& operator[](const GenericValue& name) const { return const_cast<GenericValue&>(*this)[name]; }
|
||||||
|
|
||||||
//! Member iterators.
|
//! Const member iterator
|
||||||
ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.members; }
|
/*! \pre IsObject() == true */
|
||||||
ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.members + data_.o.size; }
|
ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members); }
|
||||||
MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return data_.o.members; }
|
//! Const \em past-the-end member iterator
|
||||||
MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return data_.o.members + data_.o.size; }
|
/*! \pre IsObject() == true */
|
||||||
|
ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members + data_.o.size); }
|
||||||
|
//! Member iterator
|
||||||
|
/*! \pre IsObject() == true */
|
||||||
|
MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members); }
|
||||||
|
//! \em Past-the-end member iterator
|
||||||
|
/*! \pre IsObject() == true */
|
||||||
|
MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members + data_.o.size); }
|
||||||
|
|
||||||
//! Check whether a member exists in the object.
|
//! Check whether a member exists in the object.
|
||||||
/*!
|
/*!
|
||||||
\note It is better to use FindMember() directly if you need the obtain the value as well.
|
\note It is better to use FindMember() directly if you need the obtain the value as well.
|
||||||
*/
|
*/
|
||||||
bool HasMember(const Ch* name) const { return FindMember(name) != 0; }
|
bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); }
|
||||||
|
|
||||||
// This version is faster because it does not need a StrLen().
|
// This version is faster because it does not need a StrLen().
|
||||||
// It can also handle string with null character.
|
// It can also handle string with null character.
|
||||||
bool HasMember(const GenericValue& name) const { return FindMember(name) != 0; }
|
bool HasMember(const GenericValue& name) const { return FindMember(name) != MemberEnd(); }
|
||||||
|
|
||||||
//! Find member by name.
|
//! Find member by name.
|
||||||
/*!
|
/*!
|
||||||
\return Return the member if exists. Otherwise returns null pointer.
|
\pre IsObject() == true
|
||||||
|
\return Iterator to member, if it exists.
|
||||||
|
Otherwise returns \ref MemberEnd().
|
||||||
|
|
||||||
|
\note Earlier versions of Rapidjson returned a \c NULL pointer, in case
|
||||||
|
the requested member doesn't exist. For consistency with e.g.
|
||||||
|
\c std::map, this has been changed to MemberEnd() now.
|
||||||
*/
|
*/
|
||||||
MemberIterator FindMember(const Ch* name) {
|
MemberIterator FindMember(const Ch* name) {
|
||||||
RAPIDJSON_ASSERT(name);
|
RAPIDJSON_ASSERT(name);
|
||||||
RAPIDJSON_ASSERT(IsObject());
|
RAPIDJSON_ASSERT(IsObject());
|
||||||
|
|
||||||
SizeType len = internal::StrLen(name);
|
SizeType len = internal::StrLen(name);
|
||||||
for (MemberIterator member = MemberBegin(); member != MemberEnd(); ++member)
|
MemberIterator member = MemberBegin();
|
||||||
|
for (; member != MemberEnd(); ++member)
|
||||||
if (member->name.data_.s.length == len && memcmp(member->name.data_.s.str, name, len * sizeof(Ch)) == 0)
|
if (member->name.data_.s.length == len && memcmp(member->name.data_.s.str, name, len * sizeof(Ch)) == 0)
|
||||||
return member;
|
break;
|
||||||
|
return member;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstMemberIterator FindMember(const Ch* name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
|
ConstMemberIterator FindMember(const Ch* name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
|
||||||
|
|
||||||
// This version is faster because it does not need a StrLen().
|
// This version is faster because it does not need a StrLen().
|
||||||
@ -338,11 +497,11 @@ public:
|
|||||||
RAPIDJSON_ASSERT(IsObject());
|
RAPIDJSON_ASSERT(IsObject());
|
||||||
RAPIDJSON_ASSERT(name.IsString());
|
RAPIDJSON_ASSERT(name.IsString());
|
||||||
SizeType len = name.data_.s.length;
|
SizeType len = name.data_.s.length;
|
||||||
for (MemberIterator member = MemberBegin(); member != MemberEnd(); ++member)
|
MemberIterator member = MemberBegin();
|
||||||
|
for ( ; member != MemberEnd(); ++member)
|
||||||
if (member->name.data_.s.length == len && memcmp(member->name.data_.s.str, name.data_.s.str, len * sizeof(Ch)) == 0)
|
if (member->name.data_.s.length == len && memcmp(member->name.data_.s.str, name.data_.s.str, len * sizeof(Ch)) == 0)
|
||||||
return member;
|
break;
|
||||||
|
return member;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
ConstMemberIterator FindMember(const GenericValue& name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
|
ConstMemberIterator FindMember(const GenericValue& name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
|
||||||
|
|
||||||
@ -399,7 +558,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool RemoveMember(const Ch* name) {
|
bool RemoveMember(const Ch* name) {
|
||||||
MemberIterator m = FindMember(name);
|
MemberIterator m = FindMember(name);
|
||||||
if (m) {
|
if (m != MemberEnd()) {
|
||||||
RemoveMember(m);
|
RemoveMember(m);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -409,7 +568,7 @@ public:
|
|||||||
|
|
||||||
bool RemoveMember(const GenericValue& name) {
|
bool RemoveMember(const GenericValue& name) {
|
||||||
MemberIterator m = FindMember(name);
|
MemberIterator m = FindMember(name);
|
||||||
if (m) {
|
if (m != MemberEnd()) {
|
||||||
RemoveMember(m);
|
RemoveMember(m);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -428,7 +587,7 @@ public:
|
|||||||
RAPIDJSON_ASSERT(data_.o.members != 0);
|
RAPIDJSON_ASSERT(data_.o.members != 0);
|
||||||
RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd());
|
RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd());
|
||||||
|
|
||||||
MemberIterator last = data_.o.members + (data_.o.size - 1);
|
MemberIterator last(data_.o.members + (data_.o.size - 1));
|
||||||
if (data_.o.size > 1 && m != last) {
|
if (data_.o.size > 1 && m != last) {
|
||||||
// Move the last one to this place
|
// Move the last one to this place
|
||||||
m->name = last->name;
|
m->name = last->name;
|
||||||
|
71
include/rapidjson/internal/meta.h
Normal file
71
include/rapidjson/internal/meta.h
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#ifndef RAPIDJSON_INTERNAL_META_H_
|
||||||
|
#define RAPIDJSON_INTERNAL_META_H_
|
||||||
|
|
||||||
|
//@cond RAPIDJSON_INTERNAL
|
||||||
|
namespace rapidjson {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
template <int N> struct IntegralC { enum { Value = N }; };
|
||||||
|
template <bool Cond> struct BoolType : IntegralC<Cond> {};
|
||||||
|
struct TrueType : BoolType<true> {};
|
||||||
|
struct FalseType : BoolType<false> {};
|
||||||
|
|
||||||
|
template <typename T> struct AddConst { typedef const T Type; };
|
||||||
|
template <typename T> struct RemoveConst { typedef T Type; };
|
||||||
|
template <typename T> struct RemoveConst<const T> { typedef T Type; };
|
||||||
|
|
||||||
|
template <bool Condition, typename T1, typename T2> struct SelectIfCond;
|
||||||
|
template <typename T1, typename T2> struct SelectIfCond<true,T1,T2> { typedef T1 Type; };
|
||||||
|
template <typename T1, typename T2> struct SelectIfCond<false,T1,T2> { typedef T2 Type; };
|
||||||
|
|
||||||
|
template <typename Condition, typename T1, typename T2>
|
||||||
|
struct SelectIf : SelectIfCond<Condition::Value,T1,T2> {};
|
||||||
|
|
||||||
|
template <bool Constify, typename T>
|
||||||
|
struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
|
||||||
|
|
||||||
|
template <typename T, typename U> struct IsSame { enum { Value = false }; };
|
||||||
|
template <typename T> struct IsSame<T,T> { enum { Value = true }; };
|
||||||
|
|
||||||
|
template <typename T> struct IsConst { enum { Value = false }; };
|
||||||
|
template <typename T> struct IsConst<const T> { enum { Value = true }; };
|
||||||
|
|
||||||
|
template <typename CT, typename T>
|
||||||
|
struct IsMoreConst {
|
||||||
|
enum { Value =
|
||||||
|
( IsSame< typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>::Value
|
||||||
|
&& ( IsConst<CT>::Value >= IsConst<T>::Value ) )
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <bool Condition, typename T = void> struct EnableIfCond;
|
||||||
|
template <typename T> struct EnableIfCond<true, T> { typedef T Type; };
|
||||||
|
template <typename T> struct EnableIfCond<false, T> { /* empty */ };
|
||||||
|
|
||||||
|
template <bool Condition, typename T = void>
|
||||||
|
struct DisableIfCond : EnableIfCond<not Condition, T> {};
|
||||||
|
|
||||||
|
template <typename Condition, typename T = void>
|
||||||
|
struct EnableIf : EnableIfCond<Condition::Value, T> {};
|
||||||
|
|
||||||
|
template <typename Condition, typename T = void>
|
||||||
|
struct DisableIf : DisableIfCond<Condition::Value, T> {};
|
||||||
|
|
||||||
|
// SFINAE helpers
|
||||||
|
struct SfinaeResultTag {};
|
||||||
|
template <typename T> struct RemoveSfinaeFptr {};
|
||||||
|
template <typename T> struct RemoveSfinaeFptr<SfinaeResultTag&(*)(T)> { typedef T Type; };
|
||||||
|
|
||||||
|
#define RAPIDJSON_REMOVEFPTR_(type) \
|
||||||
|
typename ::rapidjson::internal::RemoveSfinaeFptr \
|
||||||
|
< ::rapidjson::internal::SfinaeResultTag&(*) type>::Type
|
||||||
|
|
||||||
|
#define RAPIDJSON_ENABLEIF(cond) \
|
||||||
|
typename ::rapidjson::internal::EnableIf \
|
||||||
|
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace rapidjson
|
||||||
|
//@endcond
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_INTERNAL_META_H_
|
Loading…
x
Reference in New Issue
Block a user