clang std::isspace 编译错误

clang std::isspace compilation error

以下代码在 VS 2015(更新 3)和 gcc 6.3 (C++14) 上编译良好,没有任何问题。

#include <string>
#include <locale>

int main()
{
    std::u16string ustr = u"Android";

    bool var = std::isspace(ustr[0],std::locale());

    return 0;
}

然而,在 clang/Xcode 它失败并出现以下错误

Error(s):
source_file.cpp:8:10: warning: unused variable 'var' [-Wunused-variable]
    bool var = std::isspace(ustr[0],std::locale());
         ^
In file included from source_file.cpp:2:
In file included from /usr/include/c++/v1/locale:182:
/usr/include/c++/v1/__locale:705:44: error: implicit instantiation of undefined template 'std::__1::ctype<char16_t>'
    return use_facet<ctype<_CharT> >(__loc).is(ctype_base::space, __c);
                                           ^
source_file.cpp:8:21: note: in instantiation of function template specialization 'std::__1::isspace<char16_t>' requested here
    bool var = std::isspace(ustr[0],std::locale());
                    ^
/usr/include/c++/v1/__locale:427:53: note: template is declared here
template <class _CharT> class _LIBCPP_TYPE_VIS_ONLY ctype;
                                                    ^
/usr/include/c++/v1/__locale:186:54: error: implicit instantiation of undefined template 'std::__1::ctype<char16_t>'
    return static_cast<const _Facet&>(*__l.use_facet(_Facet::id));
                                                     ^
/usr/include/c++/v1/__locale:705:12: note: in instantiation of function template specialization 'std::__1::use_facet<std::__1::ctype<char16_t> >' requested here
    return use_facet<ctype<_CharT> >(__loc).is(ctype_base::space, __c);
           ^
source_file.cpp:8:21: note: in instantiation of function template specialization 'std::__1::isspace<char16_t>' requested here
    bool var = std::isspace(ustr[0],std::locale());
                    ^
/usr/include/c++/v1/__locale:427:53: note: template is declared here
template <class _CharT> class _LIBCPP_TYPE_VIS_ONLY ctype;
                                                    ^
1 warning and 2 errors generated.

我在这里错过了什么? 有 header 包含吗?如果有,是哪一个? 如果没有,还有其他解决方法吗?

<locale> 中的 std::isspace 重载等效于(根据标准):

std::use_facet< std::ctype<charT> >(loc).is(ctype_base::space, c)

如您所见,这需要对给定的 CharT 进行 std::ctype 的特化。

标准只提供std::ctype<char>std::ctype<wchar_t>。由于 char16_t 是一个内置类型,你不能特化 std::ctype<char16_t> 所以我认为你被搞砸了。

问题是 std::isspacestd::locale 实现使用了 std::ctype 中定义的字符特征,它定义了字符类型的某些特征。

不幸的是,标准只要求 std::ctype 专门用于 charwchar_t,而不是您需要的 char16_t。似乎 MSVC 和 GCC 正在提供额外的实现(因为它有意义)。 (编辑:GCC 实际上抛出异常)。

我们不能为它添加我们自己的特化,因为 [namespace.std] 声明我们只能为用户定义类型添加特化到 namespace std

这给我们留下了几个选择:

  • 在使用 <locale> 中的 std::isspace 之前,将您的角色转换为 charwchar_t
    • 请注意,对于 char,这通常是一个 缩小转换范围,您可能不希望
  • <cctype> 切换到使用 std::isspace 的实现,它转换为 int
    • 如果类型无法在 unsigned char 中表示,则您有未定义的行为,因此这也可能不是您想要的,具体取决于您使用的类型(检查 sizeof(unsigned char)
  • 为你的性格类型写下你自己的特质(可能是现在最好的选择)
  • 提交缺陷报告,希望委员会同意你的意见,然后等待两年或更长时间才能修复 :-)
    • 或者请 clang 编写者添加这个便利(也是一个不错的主意)
  • 那样编写您自己的专业化,并接受未定义的行为

相关:C++11 对 Unicode 的支持程度如何?