在“char 类型”模板化类中使用字符串文字
Posted
技术标签:
【中文标题】在“char 类型”模板化类中使用字符串文字【英文标题】:Use string litterals in a "char type" templated class 【发布时间】:2015-12-26 17:18:05 【问题描述】:我在 C++ 中有一个模板类,它将char_type
模板参数作为字符类型,例如char
、wchar_t
、char32_t
等... 然后该类在代码。
然后在课堂上的某个地方,我填写了一个转义序列表,例如"&"
。这不起作用,因为取决于模板字符类型,我们需要使用"&"
、L"&"
、U"&"
...
有没有办法避免专门用于初始化表的模板函数,例如使用一些标准函数来转换字符串?
由于这些是转义序列,它们除了 ASCII 字符外不包含任何其他内容。
【问题讨论】:
所以你本质上需要一个多态字符串文字?嗯…… 不,我想在编译时这样做 C++ 也有编译时多态性,但我不确定这里是否可行。 @templates 不。模板是一种允许多态性的机制,但我离题了。让我考虑一下可能的解决方案。 不知道为什么会有反对票。这是一个很好的问题,而且(令人惊讶的是)我找不到骗子。 【参考方案1】:我会做以下事情:
template <typename char_type, size_t LENGTH>
constexpr std::basic_string<char_type> literal(const char (&value)[LENGTH])
using string = std::basic_string<char_type>;
string result;
result.reserve(LENGTH);
std::copy(std::begin(value), std::end(value), std::back_inserter(result));
return result; // rvo
你可以这样使用它:
// Table of escaping sequences
std::basic_string<char_type> escaping_sequences[] =
literal<char_type>("&"),
literal<char_type>("&foo"),
literal<char_type>("&bar"),
...
我已经测试过了in Ideone:
literal< char >("test") // result: std::string
literal<char32_t>("test") // result: std::basic_string<char32_t, std::char_traits<char32_t>, std::allocator<char32_t> >
literal<char16_t>("test") // result: std::basic_string<char16_t, std::char_traits<char16_t>, std::allocator<char16_t> >
未针对所有 char 类型进行测试,但希望对您有所帮助。
编辑 1
我的错,我刚刚注意到 galinette 几乎和我之前回答的一样。我的代码和 galinette 的代码之间的唯一区别是,我 使用 在编译时计算字符数, 由于使用了reserve
分配结果字符串一次,而不是使用 push_back
的自动分配LENGTH
作为模板参数。
编辑 2
可以通过在end
迭代器中减去 1 来避免最终的空字符问题:
template <typename char_type, size_t LENGTH>
constexpr std::basic_string<char_type> literal(const char (&value)[LENGTH])
using string = std::basic_string<char_type>;
string result;
result.reserve(LENGTH - 1);
std::copy(std::begin(value), std::end(value) - 1, std::back_inserter(result));
return result; // rvo
或者,使用std::copy_n
代替std::copy
:
template <typename char_type, size_t LENGTH>
constexpr std::basic_string<char_type> literal(const char (&value)[LENGTH])
using string = std::basic_string<char_type>;
string result;
result.reserve(LENGTH - 1);
std::copy_n(std::begin(value), LENGTH - 1, std::back_inserter(result));
return result; // rvo
【讨论】:
我也用过reserve!但是您的解决方案更好,因为它不计算运行时的字符数,因为使用 LENGTH 作为模板参数是个好主意。 @galinette 我今天过得多么开心......你说得对,你也在使用reserve
,但我这一天充满了误读:'(
非常感谢这个优雅的解决方案!使用此代码后只是一个小评论:我遇到了上述代码还在结果中包含最终空字符的问题(即尝试评估literalLENGTH - 1
字符并使用std::copy_n
而不是std::copy
(我会编辑答案)。跨度>
MSVC 2015,它显然具有“一些”c++14 功能,但没有“扩展 constexpr”。也许这就是原因。 msdn.microsoft.com/en-us/library/hh567368.aspx【参考方案2】:
最好的方法可能是自己定义转换函数,因为将 ASCII 转换为 UTF8/16/32 是对 char 类型的直接转换
template<typename char_type>
std::basic_string<char_type> cvtASCIItoUTFX(const char * litteral)
//We could define a faster specialization in case char_type is char
size_t s = strlen(litteral);
std::basic_string<char_type> result;
result.reserve(s);
for(size_t i=0;i<s;++i)
result.push_back((char_type)litteral[i]);
return result;
【讨论】:
【参考方案3】:由于这些是转义序列,它们除了 ASCII 字符之外不包含任何其他内容。
有没有办法避免专门用于初始化表的模板函数,例如使用一些标准函数来转换字符串?
不,因为该标准没有任何转换函数可以坚持这些特定的子集。
我建议只为表格使用外部生成器,或者如果您真的想留在 C++ 中,请使用宏。
【讨论】:
由于 ASCII 字符串是有效的 UTF8 字符串,并且由于 c++11 具有 utf8 到 utf16 的转换,所以这并不完全正确。 如果你正确地阅读了我的主张,你会发现使用超集来反驳它是没有意义的。但除此之外,标准中没有足够的转换函数。您必须手动完成。【参考方案4】:此答案仅适用于非字符串(即数字)文字
...因为只有那些被语言扩展为template<char...>
。
因为我在这上面花了一段时间,我想我不妨把它贴在这里。不适用于实际的字符文字,因为 herp derp C++.
template<char16_t... str>
struct Literal16
static constexpr char16_t arr[] = str...;
constexpr operator const char16_t*()
return arr;
;
template<char... str>
struct Literal8
static constexpr char arr[] = str...;
constexpr operator const char*()
return arr;
;
template<char... str>
struct PolyLiteral
operator const char*()
return Literal8<str...>();
operator const char16_t*()
return Literal16<str...>();
;
template<char... str> PolyLiteral<str...> operator"" _poly() return PolyLiteral<str...>();
int main()
const char* test = 123_poly;
const char16_t* test2 = 123_poly;
【讨论】:
Doh,这是一个很好的操作符黑客...不过,这可能会使代码难以阅读。【参考方案5】:如果您可以使用宏:
#define TEXT_char(text) (text)
#define TEXT_wchar_t(text) (L ## text)
//...etc
#define TEXT(type, text) (TEXT_##type(text))
int main()
const char* c = TEXT(char, "Test");
const wchar_t* w = TEXT(wchar_t, "Test");
【讨论】:
这没有回答问题。以上是关于在“char 类型”模板化类中使用字符串文字的主要内容,如果未能解决你的问题,请参考以下文章