我目前正在编写一些模板代码,其中template参数是要使用的char类型。这在引用文字字符串时会导致问题。当然,我可以使用我使用的字符串制作一个结构,但我在想是否可以制作类似的东西:
template<typename chartype, char32_t... chars>
struct tr {
/* some magic here */
};
这样tr<char32_t,U"hello world">
会导致U"hello world"
和tr<char16_t,U"Hello world">
会产生u"hello world"
tr<char,U"hello world">
会产生"hello world"
(UTF-8)。
魔术当然应该正确地将0x10000以上的代码转换为引导代码并遵循char16_t的代码以及UTF-8的正确2,3和4字节代码 在编译时。
问题是:如何使用char32_t... chars
模板参数定义给定char类型的常量C样式字符串?您可以提取字符
从它,但如何根据模板代码中的输入字符串的字符重建一个新的字符串?
注意,预处理器可以正确地定义一个字符串,例如"hello world"
,如果你愿意,可以使用合适的前缀u或U,但它不能访问字符串的各个字符以正确翻译它。
编辑:
作为模板参数的字符串在新的C ++中肯定是可能的,但是,
模板参数未声明为const char *
或类似的东西:
template <char... txt>
struct foo { ... }
允许您将foo<"hello">
编写为字符串"hello"
作为模板参数的类型。问题是如何从这些字符构建字符串。
我的意思是在某些时候你希望struct包含一个返回的字符串值:
template <char32_t... txt>
struct foo;
template <>
struct foo<> {
static const char16_t * txt() { return ""; }
};
template <char32_t a, char32_t... rest>
struct foo<a, rest...> {
static const char16_t * txt()
{
char16_t buf[100];
int k = 0;
if (a < 0x10000) buf[k++] = a;
else {
buf[k++] = 0xd800 | ((a - 0x10000) >> 10);
buf[k++] = 0xdc00 | ((a-0x10000) & 0x3ff);
}
// copy rest of string into buf + 2..99
u16strcpy(buf + k, foo<rest...>::txt());
return buf;
}
}
这个“解决方案”有几个明显的问题,一个问题是buf只有100个字符的空间,如果字符串更长则会失败。但主要的问题是我希望这在编译时发生,这看起来非常像我的运行时代码,而不是我想做的。
基本上我想要的东西是这样的:
foo<char, "hello">
会产生一些有效的字符串文字
"hello"
或u8"hello"
。
foo<char16_t, "hello">
会产生一些有效的字符串文字u"hello"
,foo<char32_t, "hello">
会产生有效的字符串文字U"hello"
。
问题在于编写模板代码以处理各种字符格式,然后涉及字符串文字。是的,你可以写一个简单的结构:
template <typename ChT> struct bar;
template <>
struct bar<char32_t> {
static const char32_t * txta = U"AAAA";
static const char32_t * txtb = U"BBBB";
};
依此类推,bar<char16_t>
有txta = u"AAAA"
等。然后参考字符串
在您的模板化代码中bar<T>::txta
等等。但是,我希望有一种方法可以直接在模板化代码中指定这些字符串,编译器会做正确的事情。换句话说,是模板化的字符串文字。
也许它应该作为一种功能添加到语言中
T<char32_t> string-literal
与U string-literal等相同
这样你就可以写
template <typename ChT>
struct foo {
static const ChT * txta = T<ChT> "AAAAA";
};
并且编译器会做正确的事。
答案 0 :(得分:0)
这似乎不合法,即使以下内容被拒绝(vs2017,标准设置为最新):
template<char const * ptr>
struct test
{};
void bar()
{
test<"testing"> t;
}
错误:无效表达式作为'ptr'的模板参数,如果在编译时尝试转换它不起作用,那么这是一个非启动性。老实说,指向数据的指针不够稳定似乎并不令人惊讶。成为模板参数。
答案 1 :(得分:0)
以下是一些使其在 C ++ 17 中工作的工具(可能可以移植到C ++ 11和C ++ 14):
模板化类的static constexpr
数据成员
您希望使用的输出文字需要一些“存储”。我建议为每个文字实例化一个唯一的类模板,例如Literal<char, 'f', 'o', 'o', '\0'>. That class can hold the data as a
静态constexpr`成员。
template<class C, C... cs>
struct Literal {
static_assert(sizeof...(cs) >= 1);
static constexpr C data[] = {cs...};// or use `std::array<C, sizeof...(cs)>`
};
template<class C, C... cs>
constexpr C Literal<C, cs...>::data[];
当然,您希望避免输入内容,例如Literal<char, 'f', 'o', 'o', '\0'>
。实现这一目标的一个有用工具是用户定义的字符串文字的以下重载。
template<class C, C... cs>
constexpr Literal<C, cs..., C('\0')> operator""_c() {// or use `auto`
return Literal<C, cs..., C('\0')>{};
}
注意输入文字如何作为非类型模板参数传递给该重载。这样,就可以“将值作为一种类型”。
用于重新编码的constexpr
算法到目前为止,您可以输入"foo"_c
来获取Literal<char, 'f', 'o', 'o', '\0'>
,其中static constexpr
数据成员的成员与"foo"
相同。接下来,您可以将Literal<char, 'f', 'o', 'o', '\0'>
传递给一个函数,该函数会返回相应const char16_t(&)[4]
的{{1}}到data
。语法可以是Literal<char16_t, ..., '\0'>
。
将tr<char16_t>("foo"_c)
转换为相应的Literal<char, ...>
的代码可以基于Literal<char16_t, ...>
算法,如下所示。
constexpr
剩下的部分是实现这些功能template<
class OutChar, class InChar, InChar... cs,
std::size_t... input_indices, std::size_t... output_indices
>
constexpr auto& tr_impl(// called by `tr` with appropriate `index_sequence`s
Literal<InChar, cs...>,
std::index_sequence<input_indices...>,
std::index_sequence<output_indices...>
) {
constexpr std::size_t outsize = sizeof...(output_indices);
using Buffer = std::array<OutChar, outsize>;
constexpr Buffer buf = encode_as<OutChar, outsize>({cs...});
return Literal<OutChar, buf[output_indices]...>::data;
}
template<class OutChar, class InChar, InChar... cs>
constexpr auto& tr(Literal<InChar, cs...> literal) {
constexpr std::size_t outsize = count_as<OutChar>({cs...});
return tr_impl<OutChar>(
literal,
std::make_index_sequence<sizeof...(cs)>{},// input indices
std::make_index_sequence<outsize>{}// output indices
);
}
和count_as
。
encode_as
最后,您可以分配给constexpr auto&
,以根据所需的字符类型验证类型和值是否等同于普通字符串文字。
constexpr auto&