在 "char type" 模板化 class 中使用字符串文字
Use string litterals in a "char type" templated class
我在 C++ 中有一个模板 class,它将字符类型作为 char_type
模板参数,例如 char
、wchar_t
、char32_t
等... class 然后在代码中使用 std::basic_string<char_type>
。
然后在 class 的某处我填充了一个 table 转义序列,例如 "&"
。这不起作用,因为取决于模板字符类型,我们需要使用 "&"
、L"&"
、U"&"
...
有没有办法避免专门用于初始化 table 的模板函数,例如使用一些标准函数来转换字符串文字?
由于这些是转义序列,因此它们只包含 ASCII 字符。
As these are escaping sequences, they do not contain anything else than ASCII characters.
Is there a way to avoid specializing the template functions for initializing the table, for instance with some standard function for converting string litterals?
否,因为标准没有任何适用于此类特定子集的转换函数。
我建议只为 table 使用外部生成器,或者如果你真的想留在 C++ 中,使用宏。
此答案仅适用于非字符串(即数字)文字
... 因为只有那些被语言扩展为 template<char...>
。
因为我在这上面花了一段时间,所以我想我也可以 post 在这里。不适用于实际字符文字,因为 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;
}
最好的方法可能是自己定义转换函数,因为将 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;
}
我会做以下事情:
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> >
尚未对所有字符类型进行测试,但希望对您有所帮助。
编辑 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
}
我在 C++ 中有一个模板 class,它将字符类型作为 char_type
模板参数,例如 char
、wchar_t
、char32_t
等... class 然后在代码中使用 std::basic_string<char_type>
。
然后在 class 的某处我填充了一个 table 转义序列,例如 "&"
。这不起作用,因为取决于模板字符类型,我们需要使用 "&"
、L"&"
、U"&"
...
有没有办法避免专门用于初始化 table 的模板函数,例如使用一些标准函数来转换字符串文字?
由于这些是转义序列,因此它们只包含 ASCII 字符。
As these are escaping sequences, they do not contain anything else than ASCII characters.
Is there a way to avoid specializing the template functions for initializing the table, for instance with some standard function for converting string litterals?
否,因为标准没有任何适用于此类特定子集的转换函数。
我建议只为 table 使用外部生成器,或者如果你真的想留在 C++ 中,使用宏。
此答案仅适用于非字符串(即数字)文字
... 因为只有那些被语言扩展为 template<char...>
。
因为我在这上面花了一段时间,所以我想我也可以 post 在这里。不适用于实际字符文字,因为 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;
}
最好的方法可能是自己定义转换函数,因为将 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;
}
我会做以下事情:
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> >
尚未对所有字符类型进行测试,但希望对您有所帮助。
编辑 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
}