Curious issue with char_traits
Howard Hinnant
hhinnant@apple.com
Tue Oct 25 15:10:00 GMT 2005
On Oct 25, 2005, at 9:16 AM, Paolo Carlini wrote:
> Hi,
>
> while answering privately a message from a user, I noticed a curious
> glitch. Consider this:
>
> --------
> #include <string>
>
> using namespace __gnu_cxx;
> using namespace std;
>
> typedef basic_string<char, char_traits<char>, allocator<char> > mystr;
> --------
>
> Well, doesn't compile!
>
> plain.cc:6: error: 'char_traits' was not declared in this scope
> plain.cc:6: error: missing '>' to terminate the template argument list
> plain.cc:6: error: template argument 2 is invalid
> plain.cc:6: error: expected unqualified-id before '>' token
>
> The problem is that our "extended" char_traits implementation
> involves a
> template struct named char_traits *both* in __gnu_cxx and in std
> (which
> uses the former). But __gnu_cxx is the namespace where all our
> extension
> facilities live and as soon as a user does 'using namespace
> __gnu_cxx;'
> (I think it can be common), then char_traits becomes ambiguous (an
> additional std:: qualifier becomes necessary)
>
> I think we should fix this, i.e., we should render std::char_traits
> robust wrt using-directives. What about renaming
> __gnu_cxx::char_traits
> to something like __gnu_cxx::__char_traits? This would fix the problem
> at issue and it would still be possible to specialize
> __gnu_cxx::__char_traits.
>
> Opinions?
I think that would help. However there are a couple of more gotchas
if we intend on char_traits<some scalar other than char and wchar_t>
to be robust. Consider:
#include <string>
#include <ext/algorithm>
template <class T> void copy_n(T, long, int);
int main()
{
copy_n(std::char_traits<unsigned char>(), 0, 0);
}
Now, no using statements are involved. But the contents of __gnu_cxx
is still polluting the namespace. Because of an implementation
detail of std::char_traits (it derives from something in __gnu_cxx),
__gnu_cxx is searched when making an unqualified call with
std::char_traits as a parameter. Here is perhaps a more insidious
example of the same problem:
#include <string>
#include <ext/algorithm>
template <class T> void copy_n(T, long, int);
int main()
{
copy_n(std::basic_string<unsigned char>(), 0, 0);
}
We still get pollution from __gnu_cxx because
std::char_traits<unsigned char> is associated with
std::basic_string<unsigned char>.
In general it is dangerous to derive from anything in __gnu_cxx, even
as an implementation detail, unless __gnu_cxx contains nothing but
__xxx (or _X) identifiers.
-Howard
More information about the Libstdc++
mailing list