Naturally it isn't possible to instantiate a facet, since a facet doesn't encapsulate any specific functionality, instead leaving that to specific classes derived from facet, such as collate<C>, etc.
Ie, the facet class is designed to be a base class.
For this reason, to prevent a facet being instantiated directly, its constructor is protected and destructor is virtual (to ensure proper destruction of derived-class objects):
1 2 3 4 5 6 7 8 9 10
|
class locale::facet
{
protected:
explicit facet(size_t refs = 0);
virtual ~facet();
facet(const facet&) = delete;
void operator=(const facet&) = delete;
};
|
However, now consider the standard facet collate<C>, which is derived from facet:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
template<typename C>
class collate : public locale::facet
{
public:
/// ...
protected:
~collate(); /// note: protected destructor
virtual int do_compare(
const C* b, const C* e,
const C* b2, const C* e2) const;
virtual string_type do_transform(
const C* b,
const C* e) const;
virtual long do_hash(const C* b,
const C* e) const;
};
|
Notice that here too, the destructor is protected. Therefore you won't be able to instantiate a collate<char>. If you try to do so, you will get an error:
The error is:
error: 'std::collate<_CharT>::~collate() [with _CharT = char]' is protected|
|
Yet, the collate<C> template class's protected members (do_compare(), do_transform() and do_hash()) all contain encapsulated functionality and there was no need for the standard facet collate<C> to have been declared with a protected dtor.
For this reason, to create a collate<C>, we need to be first derive a class from collate<C>, which can then be instantiated!
1 2 3 4 5 6 7 8 9 10 11
|
template<typename C>
class My_collate : public collate<C>
{
public:
explicit My_collate(size_t r = 0) :
collate<C> {r}
{
}
};
My_collate<char> mcolc;
|
This successfuly creates a My_collate<char> (which is a collate<char> by derivation).
Just to prove that My_collate<char> encapsulates inherited functionality, I have successfully tested it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
|
void print(const string& s1, const string& s2,
const int& rslt)
{
string srslt {};
switch(rslt)
{
case 0:
srslt = "equal";
break;
case 1:
srslt = "s1 > s2";
break;
case -1:
srslt = "s1 < s2";
break;
}
cout << "comparison of " << s1 << " and " << s2
<< " using the mcolc facet : "
<< srslt << endl;
}
void test(const string& s1, const string& s2)
{
/// since compare() operates on char[]s
const char* s1b = s1.data(); /// start of data
const char* s1e = s1b + s1.size(); /// end of data
const char* s2b = s2.data(); /// start of data
const char* s2e = s2b + s2.size(); /// end of data
int rslt = mcolc.compare(s1b, s1e, s2b, s2e);
/// display results
print(s1, s2, rslt);
}
int main()
{
test("Hello", "Hello");
test("Hello", "hello");
test("hello", "Hello");
}
|
https://ideone.com/D6zrbr
Here's the output:
comparison of Hello and Hello using the mcolc facet : equal
comparison of Hello and hello using the mcolc facet : s1 < s2
comparison of hello and Hello using the mcolc facet : s1 > s2
|
So, my question is: Why do standard facets such as collate<C> have a protected destructor, so as to prevent direct instantiation, when they already encapsulate the full required functionality?
Thanks.