【问题标题】:string literal - template conversion between char types字符串文字 - 字符类型之间的模板转换
【发布时间】:2015-10-08 03:26:51
【问题描述】:

我想编写一个如下所示的函数:

template <typename CharT>
std::basic_string<CharT> convert(char const *);

并按如下方式使用:

convert<char>("Hello World!");     //  "Hello World!"
convert<wchar_t>("Hello World!");  // L"Hello World!"
convert<char16_t>("Hello World!"); // u"Hello World!"
convert<char32_t>("Hello World!"); // U"Hello World!"

我可以使用 std::codecvt 和 co,但我发现它几乎毫无意义,因为使用一些添加 LuU 的宏会更容易,成本为 0。

不幸的是,模板和宏的作用不同......所以我的问题来了:有什么方法可以混合它们吗?还是有更好的办法?

我的主要目标是避免代码的重复(专业化):我正在编写的一些函数是 CharT 模板化并使用字符串文字,这将是唯一的区别。举个例子:

template <typename CharT>
void foo (std::vector<std::basic_string<CharT>> const & vec, 
          std::basic_string<CharT> str = convert<CharT>("default"));

这样可以避免为每个 char 类型专门化 foo()。

非常感谢您的帮助

【问题讨论】:

  • 我认为这里不需要专业化,只需使用例如codecvt char 作为“源”类型,CharT 作为“目标”类型?
  • 确实,后来我已经在考虑了。已编辑,谢谢。
  • @JoachimPileborg 是的,但这仍然是运行时计算。 OP 希望避免这种情况,因为它们是字符串文字,添加某个前缀就可以了。
  • 在那种情况下,宏不是唯一的方法吗?我不确定,但我认为宏连接运算符## 可以将前缀附加到字符串常量。除非这可以用operator"" 来完成?不过我对此表示怀疑。
  • 在整个程序逻辑中仅使用一种类型的字符串文字(例如 u8"default")和一种类型的 std::basic_string(例如包含 utf8 的 std::string)。然后问题就不再存在了。

标签: c++ templates char wchar-t


【解决方案1】:

已编辑:这将从C++11 开始工作。由于运算符不能是模板,您可以将运算符重载更改为 convert 函数。

#include <string>

std::basic_string<char> operator ""_s(const char * str, std::size_t len) {
    return std::basic_string<char> (str, str + len);
}

std::basic_string<char16_t> operator ""_u(const char * str, std::size_t len) {
    return std::basic_string<char16_t> (str, str + len);
}

std::basic_string<char32_t> operator ""_U(const char * str, std::size_t len) {
    return std::basic_string<char32_t> (str, str + len);
}

std::basic_string<wchar_t> operator ""_L(const char * str, std::size_t len) {
    return std::basic_string<wchar_t> (str, str + len);
}


int main() {
    std::string s1    = "Hello World!"_s;
    std::u16string s2 = "Hello World!"_u;
    std::u32string s3 = "Hello World!"_U;
    std::wstring s4   = "Hello World!"_L;
    return 0;
}

查看 LIVE DEMO 工作。

【讨论】:

  • 感谢您的回答,但恐怕您需要在文字前加上 LuU(这正是我想要避免的)。在这里你只生成 std​​::basic_strings.
  • @JemCpp 我不需要添加任何前缀,只需添加s_s 后缀即可。
  • 看看this ideonedocumentation:参数是charwchar_tchar16_tchar32_t,不仅仅是char
  • 好的,您编辑的代码有所改进,但仍然存在问题:这不会产生相同的 Xstring。在std::wstring(L"Jérémy")"Jérémy"_L 之间进行比较(参见demo)我可能会接受它,因为我很少有机会使用重音或特定字符。
【解决方案2】:

我终于有了使用宏来生成函数 foo 的每 4 个重载的想法。

template <typename CharT>
void foo (std::vector<std::basic_string<CharT>> const & vec, 
          std::basic_string<CharT> str = convert<CharT>("default"));

变成

#define FOO(CharT, prefix) \
void foo (std::vector<std::basic_string<CharT>> const & vec, \
          std::basic_string<CharT> str = prefix ## "default");

我只需要添加

FOO(char, )
FOO(wchar_t, L)
FOO(char16_t, u)
FOO(char32_t, U)

我也可以将四行放入另一个宏 GENERATE 中,这样我就可以简单地调用

GENERATE(FOO)

我知道宏...但我已经达到了避免代码重复的主要目标。 :-)

感谢大家的帮助!

【讨论】:

    猜你喜欢
    • 2014-10-01
    • 2015-05-24
    • 2018-07-05
    相关资源
    最近更新 更多