为不同的字符串拟合字符串文字 类
Fitting string literals for different string classes
问题
我正在实施 class,我想让用户通过模板参数。我目前无法使字符串文字 适合 选择的字符串类型:一旦我决定使用文字前缀("hello"
vs. L"hello"
vs. u"hello"
与 U"hello"
),我得到所有不兼容字符串的编译错误 classes.
玩具示例
例如,考虑以下代码(使用 --std=c++11
编译):
#include <string>
template<typename StringType>
void hello_string()
{
StringType result("hello");
}
int main()
{
// works
hello_string<std::string>();
hello_string<std::basic_string<char>>();
// the code below does not compile
hello_string<std::wstring>();
hello_string<std::basic_string<unsigned char>>();
hello_string<std::u16string>();
}
函数hello_string()
展示了我想做的事情的本质:将字符串类型作为模板参数,并将字符串文字分配给这种类型的变量。
可能的解决方法
解决我的问题的一种方法是实现 hello_string()
函数的几个特化。问题是这会导致每个字符串文字都有多个副本——每个字符串文字前缀一个。我觉得这样比较丑陋,一定有更好的办法。
另一种方法是选择 "normal" 字符串文字作为默认值,并让函数转换为不同的字符串类型。虽然这可以避免代码重复,但它会引入一些实际上不变的东西的不必要的转换。
你可以给自己做一个宏。首先定义一个包装字符选择的结构:
namespace details {
template<typename T>
struct templ_text;
template<>
struct templ_text <char>
{
typedef char char_type;
static const char_type * choose(const char * narrow, const wchar_t * wide, const char16_t* u16, const char32_t* u32) { return narrow; }
static char_type choose(char narrow, wchar_t wide, char16_t u16, char32_t u32) { return narrow; }
};
template<>
struct templ_text < wchar_t >
{
typedef wchar_t char_type;
static const char_type* choose(const char * narrow, const wchar_t * wide, const char16_t* u16, const char32_t* u32) { return wide; }
static char_type choose(char narrow, wchar_t wide, char16_t u16, char32_t u32) { return wide; }
};
template<>
struct templ_text < char16_t >
{
typedef char16_t char_type;
static const char_type* choose(const char * narrow, const wchar_t * wide, const char16_t* u16, const char32_t* u32) { return u16; }
static char_type choose(char narrow, wchar_t wide, char16_t u16, char32_t u32) { return u16; }
};
template<>
struct templ_text < char32_t >
{
typedef char32_t char_type;
static const char_type* choose(const char * narrow, const wchar_t * wide, const char16_t* u16, const char32_t* u32) { return u32; }
static char_type choose(char narrow, wchar_t wide, char16_t u16, char32_t u32) { return u32; }
};
}
把它包装成一个漂亮的宏:
#define TEMPL_TEXT(Ch, txt) details::templ_text<Ch>::choose(txt, L##txt, u##txt, U##txt)
那么你的函数将是:
template<typename StringType>
void hello_string()
{
StringType result(TEMPL_TEXT(typename StringType::value_type, "Hello"));
}
我认为未使用的字符串副本将被优化掉。
问题
我正在实施 class,我想让用户通过模板参数。我目前无法使字符串文字 适合 选择的字符串类型:一旦我决定使用文字前缀("hello"
vs. L"hello"
vs. u"hello"
与 U"hello"
),我得到所有不兼容字符串的编译错误 classes.
玩具示例
例如,考虑以下代码(使用 --std=c++11
编译):
#include <string>
template<typename StringType>
void hello_string()
{
StringType result("hello");
}
int main()
{
// works
hello_string<std::string>();
hello_string<std::basic_string<char>>();
// the code below does not compile
hello_string<std::wstring>();
hello_string<std::basic_string<unsigned char>>();
hello_string<std::u16string>();
}
函数hello_string()
展示了我想做的事情的本质:将字符串类型作为模板参数,并将字符串文字分配给这种类型的变量。
可能的解决方法
解决我的问题的一种方法是实现 hello_string()
函数的几个特化。问题是这会导致每个字符串文字都有多个副本——每个字符串文字前缀一个。我觉得这样比较丑陋,一定有更好的办法。
另一种方法是选择 "normal" 字符串文字作为默认值,并让函数转换为不同的字符串类型。虽然这可以避免代码重复,但它会引入一些实际上不变的东西的不必要的转换。
你可以给自己做一个宏。首先定义一个包装字符选择的结构:
namespace details {
template<typename T>
struct templ_text;
template<>
struct templ_text <char>
{
typedef char char_type;
static const char_type * choose(const char * narrow, const wchar_t * wide, const char16_t* u16, const char32_t* u32) { return narrow; }
static char_type choose(char narrow, wchar_t wide, char16_t u16, char32_t u32) { return narrow; }
};
template<>
struct templ_text < wchar_t >
{
typedef wchar_t char_type;
static const char_type* choose(const char * narrow, const wchar_t * wide, const char16_t* u16, const char32_t* u32) { return wide; }
static char_type choose(char narrow, wchar_t wide, char16_t u16, char32_t u32) { return wide; }
};
template<>
struct templ_text < char16_t >
{
typedef char16_t char_type;
static const char_type* choose(const char * narrow, const wchar_t * wide, const char16_t* u16, const char32_t* u32) { return u16; }
static char_type choose(char narrow, wchar_t wide, char16_t u16, char32_t u32) { return u16; }
};
template<>
struct templ_text < char32_t >
{
typedef char32_t char_type;
static const char_type* choose(const char * narrow, const wchar_t * wide, const char16_t* u16, const char32_t* u32) { return u32; }
static char_type choose(char narrow, wchar_t wide, char16_t u16, char32_t u32) { return u32; }
};
}
把它包装成一个漂亮的宏:
#define TEMPL_TEXT(Ch, txt) details::templ_text<Ch>::choose(txt, L##txt, u##txt, U##txt)
那么你的函数将是:
template<typename StringType>
void hello_string()
{
StringType result(TEMPL_TEXT(typename StringType::value_type, "Hello"));
}
我认为未使用的字符串副本将被优化掉。