I have since learnt:
It is if a name is present ("C").
If a name is given it then does
setlocale(LC_ALL, loc.name.c_str());
So that means the standard is causing an all-category set.
Correct.
This looks like a flaw in the C++ standard.
It isn't. Well, "flaw" is a bit ambiguous, but the problem which I think
that you're implying doesn't exist.
If the current locale happens to be the C locale, then the result of:
std::locale(std::locale(), "C", std::locale::ctype)
will actually be the C locale, as you're taking the LC_CTYPE category from
the C locale and the other categories from the C locale also. The
implementation recognises this and gives the resulting locale the name
"C". So there's no error in the resulting locale having the name "C", nor
in std::locale::global calling setlocale(LC_ALL, "C").
Even if you construct a "heterogeneous" locale by combining categories
from different locales, there's no problem with std::locale::global
calling setlocale(LC_ALL, ...), provided that the complete locale can be
described by a string which is acceptable to setlocale().
Bear in mind that the C standard says:
7.11.1.1 The setlocale function
Synopsis
[#1]
#include <locale.h>
char *setlocale(int category, const char *locale);
Description
...
[#7] A null pointer for locale causes the setlocale function
to return a pointer to the string associated with the
category for the program's current locale; the program's
locale is not changed.175)
[#8] The pointer to string returned by the setlocale
function is such that a subsequent call with that string
value and its associated category will restore that part of
the program's locale. The string pointed to shall not be
modified by the program, but may be overwritten by a
subsequent call to the setlocale function.
...
175The implementation shall arrange to encode in a string
the various categories due to a heterogeneous locale when
category has the value LC_ALL.
So, if you create a heterogeneous locale by way of multiple setlocale()
calls with different categories, setlocale(LC_ALL, NULL) must return a
string such that setlocale(LC_ALL, str) will restore that locale.
It only becomes tricky if you want to mix your own setlocale() calls with
calls to std::locale::global(). The latter calls the former (where
possible), but the former doesn't touch the C++ global locale. The
construction which I gave earlier changes a single category of the C++
locale, then updates the C locale to match it.
Provided that the C and C++ locales were previously "in sync", the effect
is "as if" setlocale() had been called for a single category; it updates
all categories, but only one of them actually differs from its previous
setting. If the C and C++ locales were out of sync, the call will
resynchronise them. You might consider that a flaw; I consider it a case
of "don't do that".
I think (but don't know for certain) that it should suffice to use:
std::locale::global(std::locale(setlocale(LC_ALL, NULL)));
to synchronise the C++ locale to the C locale, in the event that the two
have become desynchronised by explicit setlocale() calls.