BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslmf_istransparentpredicate

Detailed Description

Outline

Purpose

Support detection of whether a predicate functor is transparent.

Classes

See also
bslstl_map, bslstl_set

Description

This component provides a metafunction, bslmf::IsTransparentPredicate, that can be used to detect whether a comparator is transparent (supports heterogeneous comparisons). If the comparator has a nested type named is_transparent, the template inherits from true_type, otherwise it inherits from false_type.

Usage

This section illustrates intended use of this component.

Example 1: Specifying Behavior Of Comparator

In this example, we demonstrate the use of IsTransparentPredicate to determine different comparator's behavior. Our goal is to create an overload of an associative container's method that participates in overload resolution only if the comparator is transparent, otherwise we fall back on a default behavior.

First, we define simple container, Vector, that is used as a foundation for our associative container:

template <class TYPE>
class Vector {
// DATA
const TYPE * d_begin_p; // pointer to the beginning
const TYPE * d_end_p; // pointer to the end
public:
// CREATORS
Vector(const TYPE *first, const TYPE *last)
// Construct an object that references the specified 'first' and
// 'last' items in the sequence.
: d_begin_p(first)
, d_end_p(last)
{
}
// ACCESSORS
const TYPE *begin() const
// Return a reference providing non-modifiable access to the first
// object in the underlying sequence.
{
return d_begin_p;
}
const TYPE *end() const
// Return a reference providing non-modifiable access to the last
// object in the underlying sequence.
{
return d_end_p;
}
};
T::iterator end(T &container)
Definition bslstl_iterator.h:1523

Then we define simple type, String, that is used as a key. Note that we have comparison operators that allow to compare both two String objects and String object with character sequence.

class String {
// CLASS DATA
static int s_numObjectsCreated; // total number of created instances
// DATA
const char *d_data_p; // reference to a string
public:
// CLASS METHODS
static int numObjectsCreated()
// Return the total number of created instances of class 'String'.
{
return s_numObjectsCreated;
}
// CREATORS
String()
// Construct an empty string
: d_data_p("")
{
++s_numObjectsCreated;
}
String(const char *data) // IMPLICIT
// Construct a string that references the specified 'data'. The
// behavior is undefined unless 'data' points to a null-terminated
// string.
: d_data_p(data)
{
++s_numObjectsCreated;
}
// FREE FUNCTIONS
friend bool operator<(const String& lhs, const String& rhs)
// Return 'true' if the value of the specified 'lhs' string is
// lexicographically less than that of the specified 'rhs' string,
// and 'false' otherwise.
{
const char *lhsData = lhs.d_data_p;
const char *rhsData = rhs.d_data_p;
while (true) {
if (*lhsData < *rhsData) {
return true; // RETURN
}
else if (*lhsData > *rhsData || *lhsData == '\0') {
return false; // RETURN
}
++lhsData;
++rhsData;
}
}
friend bool operator<(const String& lhs, const char *rhs)
// Return 'true' if the value of the specified 'lhs' string is
// lexicographically less than the specified 'rhs' character
// sequence, and 'false' otherwise.
{
const char *lhsData = lhs.d_data_p;
while (true) {
if (*lhsData < *rhs) {
return true; // RETURN
}
else if (*lhsData > *rhs || *lhsData == '\0') {
return false; // RETURN
}
++lhsData;
++rhs;
}
}
friend bool operator<(const char *lhs, const String& rhs)
// Return 'true' if the specified 'lhs' character sequence is
// lexicographically less than the value of the specified 'rhs'
// string, and 'false' otherwise.
{
const char *rhsData = rhs.d_data_p;
while (true) {
if (*lhs < *rhsData) {
return true; // RETURN
}
else if (*lhs > *rhsData || *lhs == '\0') {
return false; // RETURN
}
++lhs;
++rhsData;
}
}
};
int String::s_numObjectsCreated = 0;
bool operator<(const MetricId &lhs, const MetricId &rhs)
BSLS_KEYWORD_CONSTEXPR CONTAINER::value_type * data(CONTAINER &container)
Definition bslstl_iterator.h:1231

Next we define our associative container. Note that we use IsTransparentPredicate for a method with enable_if in the return type. This adds our function template into the function overload resolution set if and only if the comparison function object is considered transparent, using a technique known as "SFINAE".

template <class t_COMPARATOR>
class FlatStringSet {
// DATA
t_COMPARATOR d_comparator; // comparison object
Vector<String> d_data; // stores the data
public:
// TYPES
typedef const String * const_iterator;
// CREATORS
template <class INPUT_ITERATOR>
FlatStringSet(INPUT_ITERATOR first,
INPUT_ITERATOR last,
const t_COMPARATOR& comparator = t_COMPARATOR());
// Create a set, and insert each 'String' object in the sequence
// starting at the specified 'first' element, and ending
// immediately before the specified 'last' element, ignoring those
// keys having a value equivalent to that which appears earlier in
// the sequence. Optionally specify a 'comparator' used to order
// keys contained in this object. If 'comparator' is not supplied,
// a default-constructed object of the (template parameter) type
// 't_COMPARATOR' is used. This operation has 'O[N]' complexity,
// where 'N' is the number of elements between 'first' and 'last'.
// The (template parameter) type 'INPUT_ITERATOR' shall meet the
// requirements of an input iterator defined in the C++11 standard
// [24.2.3] providing access to values of a type convertible to
// 'String', and 'String' must be 'emplace-constructible' from '*i'
// into this set, where 'i' is a dereferenceable iterator in the
// range '[first .. last)'. The behavior is undefined unless
// 'first' and 'last' refer to a sequence of valid values where
// 'first' is at a position at or before 'last', the range is
// ordered according to 't_COMPARATOR', and there are no duplicates
// in the range.
// ACCESSORS
const_iterator begin() const;
// Return an iterator providing non-modifiable access to the first
// 'String' object in the ordered sequence of 'String' objects
// maintained by this set, or the 'end' iterator if this set is
// empty.
const_iterator end() const;
// Return an iterator providing non-modifiable access to the
// past-the-end element in the ordered sequence of 'String' objects
// maintained by this set.
const_iterator find(const String& key) const
// Return an iterator to the element that compares equal to the
// specified 'key' if such an element exists, and an end iterator
// otherwise.
//
// Note: implemented inline due to Sun CC compilation error.
{
for (const_iterator first = begin(); first != end(); ++first) {
if (d_comparator(key, *first)) {
return end(); // RETURN
}
if (!d_comparator(*first, key)) {
return first; // RETURN
}
}
return end();
}
template <class t_KEY>
typename bsl::enable_if<IsTransparentPredicate<t_COMPARATOR,
t_KEY>::value,
const_iterator>::type
find(const t_KEY& key) const
// Return an iterator to the element that compares equal to the
// specified 'key' if such an element exists, and an end iterator
// otherwise.
//
// Note: implemented inline due to Sun CC compilation error.
{
for (const_iterator first = begin(); first != end(); ++first) {
if (d_comparator(key, *first)) {
return end(); // RETURN
}
if (!d_comparator(*first, key)) {
return first; // RETURN
}
}
return end();
}
int size() const;
// Return the number of elements in this container.
};
// CREATORS
template <class t_COMPARATOR>
template <class INPUT_ITERATOR>
FlatStringSet<t_COMPARATOR>::FlatStringSet(INPUT_ITERATOR first,
INPUT_ITERATOR last,
const t_COMPARATOR& comparator)
: d_comparator(comparator),
d_data(first, last)
{
}
// ACCESSORS
template <class t_COMPARATOR>
typename FlatStringSet<t_COMPARATOR>::const_iterator
FlatStringSet<t_COMPARATOR>::begin() const
{
return d_data.begin();
}
template <class t_COMPARATOR>
typename FlatStringSet<t_COMPARATOR>::const_iterator
FlatStringSet<t_COMPARATOR>::end() const
{
return d_data.end();
}
template <class t_COMPARATOR>
int FlatStringSet<t_COMPARATOR>::size() const
{
return static_cast<int>(end() - begin());
}
bsl::size_t size(const TYPE &array)
Return the number of elements in the specified array.
T::iterator begin(T &container)
Definition bslstl_iterator.h:1495
Definition bslmf_enableif.h:525

Then we define two comparators. These classes are completely identical except that one defines an is_transparent type, and the other does not.

struct TransparentComp
// This class can be used as a comparator for containers. It has a
// nested type 'is_transparent', so it is classified as transparent by
// the 'bslmf::IsTransparentPredicate' metafunction and can be used for
// heterogeneous comparison.
{
// TYPES
typedef void is_transparent;
// ACCESSORS
template <class LHS, class RHS>
bool operator()(const LHS& lhs, const RHS& rhs) const
// Return 'true' if the specified 'lhs' is less than the specified
// 'rhs' and 'false' otherwise.
{
return lhs < rhs;
}
};
struct NonTransparentComp
// This class can be used as a comparator for containers. It has no
// nested type 'is_transparent', so it is classified as
// non-transparent by the 'bslmf::IsTransparentPredicate' metafunction
// and can not be used for heterogeneous comparison.
{
template <class LHS, class RHS>
bool operator()(const LHS& lhs, const RHS& rhs) const
// Return 'true' if the specified 'lhs' is less than the specified
// 'rhs' and 'false' otherwise.
{
return lhs < rhs;
}
};

Next we create an array of String objects and two FlatStringSet objects, basing on this array and having different comparators, transparent and non-transparent. Note that creation of FlatStringSet object does not increase number of created String objects, because it just holds pointers to these objects, but does not copy them.

int OBJECTS_NUMBER = String::numObjectsCreated();
assert(0 == OBJECTS_NUMBER);
String data[] = { "1", "2", "3", "5" };
enum { dataSize = sizeof data / sizeof *data };
assert(OBJECTS_NUMBER + 4 == String::numObjectsCreated());
OBJECTS_NUMBER = String::numObjectsCreated();
FlatStringSet<NonTransparentComp> nts(data, data + dataSize);
FlatStringSet< TransparentComp> ts(data, data + dataSize);
assert(4 == nts.size() );
assert(4 == ts.size() );
assert(OBJECTS_NUMBER == String::numObjectsCreated());

Then we call find method of set, having non-transparent comparator. Explicit creation of temporary String object predictably increases the number of created String objects. But using character sequence as a parameter for find method increases it too. Because comparison operator that accepts two String objects is used instead of operator that accepts String and char sequence, so String constructor is called implicitly.

assert(nts.begin() + 0 == nts.find(String("1")) );
assert(nts.begin() + 1 == nts.find(String("2")) );
assert(nts.begin() + 2 == nts.find(String("3")) );
assert(nts.begin() + 3 == nts.find(String("5")) );
assert(nts.end() == nts.find(String("6")) );
assert(OBJECTS_NUMBER + 5 == String::numObjectsCreated());
OBJECTS_NUMBER = String::numObjectsCreated();
assert(nts.begin() + 0 == nts.find( "1" ) );
assert(nts.begin() + 1 == nts.find( "2" ) );
assert(nts.begin() + 2 == nts.find( "3" ) );
assert(nts.begin() + 3 == nts.find( "5" ) );
assert(nts.end() == nts.find( "6" ) );
assert(OBJECTS_NUMBER + 5 == String::numObjectsCreated());
OBJECTS_NUMBER = String::numObjectsCreated();

Finally we call find method of set, having transparent comparator. Explicit creation of temporary String object still increases the number of created String objects. But using character sequence as a parameter for find method does not. Because comparison operator that accepts String and char sequence is available and more appropriate then operator accepting two String objects. So there is no need for implicit constructor invocation.

assert( ts.begin() + 0 == ts.find(String("1")) );
assert( ts.begin() + 1 == ts.find(String("2")) );
assert( ts.begin() + 2 == ts.find(String("3")) );
assert( ts.begin() + 3 == ts.find(String("5")) );
assert( ts.end() == ts.find(String("6")) );
assert(OBJECTS_NUMBER + 5 == String::numObjectsCreated());
OBJECTS_NUMBER = String::numObjectsCreated();
assert( ts.begin() + 0 == ts.find( "1" ) );
assert( ts.begin() + 1 == ts.find( "2" ) );
assert( ts.begin() + 2 == ts.find( "3" ) );
assert( ts.begin() + 3 == ts.find( "5" ) );
assert( ts.end() == ts.find( "6" ) );
assert(OBJECTS_NUMBER == String::numObjectsCreated());