7

我在 C++ 中有一个模板类,它将char_type字符类型作为模板参数,例如char, wchar_t,char32_t等......然后std::basic_string<char_type>在代码中使用该类。

然后在课堂上的某个地方,我填写了一个转义序列表,例如"&amp;". 这不起作用,因为取决于模板字符类型,我们需要使用"&amp;", L"&amp;", U"&amp;"...

有没有办法避免专门用于初始化表的模板函数,例如使用一些标准函数来转换字符串文字?

由于这些是转义序列,它们除了 ASCII 字符之外不包含任何其他内容。

4

4 回答 4

4

我会做以下事情:

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>("&amp"),
    literal<char_type>("&foo"),
    literal<char_type>("&bar"),
    ...
}

我已经在 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 的代码之间的唯一区别是我是分配结果字符串一次,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
}
于 2015-09-29T13:20:26.367 回答
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;
}
于 2015-09-29T10:49:55.790 回答
1

由于这些是转义序列,它们除了 ASCII 字符之外不包含任何其他内容。

有没有办法避免专门用于初始化表的模板函数,例如使用一些标准函数来转换字符串文字?

不,因为该标准没有任何转换功能可以坚持这些特定的子集。

我建议只为表使用外部生成器,或者如果您真的想留在 C++ 中,则使用宏。

于 2015-09-29T10:15:36.870 回答
0

此答案仅适用于非字符串(即数字)文字

...因为只有那些被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;
}
于 2015-09-29T10:25:15.413 回答