Provide a base class for bslstl::StringRef
.
More...
Detailed Description
- Outline
-
-
- Purpose:
- Provide a base class for
bslstl::StringRef
.
-
- Classes:
-
-
- Description:
- Initially, this component provided a complex-constrained, in-core (value-semantic) attribute class,
bslstl::StringRefData
, that represented a reference to character string data. Note that bslstl::StringRefData
was intended for use as a base class for bslstl::StringRef
and as parameter of bsl::string
constructor, enabling a conversion from bslstl::StringRef
to bsl::string
without having a cyclic dependency among these three classes.
- But nowadays it only provides compatibility between the two constructors of
bsl::string
(implicit constructor, accepting StringRefData
object by value and explicit constructor, accepting bsl::string_view
object by value) to allow existing users of bslstl::StringRef
not to change their code.
- The dependencies between these components are shown on the following diagram:
+-----------------------+
| |
/--------o bslstl::StringRef |
/ | |
/ +-----------------------+
/ |
/ |
+------------------+ +----------V------------+
| | | |
| bsl::string o--------| bslstl::StringRefData |
| | | |
+--------------o---+ +-----------------------+
\ |
\ |
\ +----------V------------+
\ | |
\-------| bsl::string_view |
| |
+-----------------------+
-
- Usage:
- This section illustrates intended use of this component.
-
- Example 1: Breaking Cyclic Dependency Between String and StringRef:
- In this example we demonstrate how
bslstl::StringRefData
allows us to break the cyclic dependency between hypothetical String
and StringRef
classes.
- Objects of our
String
and StringRef
classes need to be convertible to each other. However, only one of these classes can depend on the definition of the other one, otherwise they will be cyclically dependent.
- First, we define a hypothetical
String
class, whose implementation is intentionally simple and contains only the essential constructors and accessor methods; the important thing to notice is that String
does not depend on StringRef
, which has not been defined yet: namespace Usage {
class String {
private:
const char *d_begin_p;
const char *d_end_p;
public:
typedef const char *const_iterator;
String(bslstl::StringRefData<char> const& stringRef)
: d_begin_p(stringRef.data())
, d_end_p(stringRef.data() + stringRef.length())
{}
const char *data() const
{
return d_begin_p;
}
std::size_t length() const
{
return static_cast<std::size_t>(d_end_p - d_begin_p);
}
};
Notice that the constructor of String
takes a bslstl::StringRefData
argument and then uses its members data
and length
to initialize the string object.
- Then, we define a hypothetical
StringRef
class, whose instances can be initialized either with a String
object (to enable the conversion from String
to StringRef
) or with two const char *
pointers: class StringRef : public bslstl::StringRefData<char>
{
public:
StringRef(const char *begin, const char *end)
: bslstl::StringRefData<char>(begin, end)
{}
StringRef(const String& str)
: bslstl::StringRefData<char>(str.data(), str.data() + str.length())
{}
};
}
Note that StringRef
also derives from bslstl::StringRefData
so that an object of StringRef
can be passed to the constructor of String
as a reference to bslstl::StringRefData
, which enables the conversion from StringRef
to String
.
- Finally, we verify that the conversions between
String
and StringRef
work: using Usage::String;
using Usage::StringRef;
const char str[] = "test string";
StringRef strRef(str, str + sizeof(str));
String strObj = strRef;
StringRef strRf2 = strObj;
assert(strObj.data() == strRef.data());
assert(strObj.length() == strRef.length());
assert(strObj.data() == strRf2.data());
assert(strObj.length() == strRf2.length());
Define Documentation