在编译时将const char *转换为const char_type *

4

请考虑以下代码:

using char_type = /*implementation defined*/;

void foo(const char_type*);

int main()
{
    foo("Hello World!");
}

字符串字面量"Hello World!"是一个const char*,根据实现方式,它可能无法转换为const char_type*。我希望我的代码在不同的实现之间具有可移植性,因此我想定义一个字面量来逐个字符进行转换(这种类型的转换被保证可以工作)。
consteval const char_type* operator"" _s(const char*, size_t);

然后像这样使用 foo("Hello World!"_s)。但是我能想到的唯一实现方式是使用new来分配空间和std::copy,但这会非常慢。我希望能在编译时进行转换,幸运的是我可以使用C++20和consteval关键字来确保对该函数的调用始终产生一个常量表达式(用户定义的字面量仍然是普通函数,它们可以在运行时调用)。有什么好的实现方法吗?


2
也许可以使用模板,例如 std::basic_string 用于处理不同的字符类型?你也可以采用微软的方式,使用宏自动添加适当的前缀到所有字符串字面量中,例如 #define T(s) L ## s 或类似的方式,然后使用 foo(T("Hello world")) - Some programmer dude
如果T和U不相等,则无法将std::basic_string<T>转换为std::basic_string<U>,此外它不能在编译时使用。我从未听说过这种微软的方式,它是如何工作的? - user7769147
指针需要内存来指向。consteval函数不能神奇地从无处产生内存。 - n. m.
@n. '代词' m. 实际上使用模板,例如可以在编译时连接字符串。 这个答案 解释了如何做到这一点,即使它只适用于 std::string_view 的左值。 - user7769147
嗯,看起来需要使用非类型模板参数,但这在所有地方都还没有实现。 - n. m.
1个回答

3

这种转换可以通过两个步骤来实现:首先,在编译时构造函数中声明一个类,该类可以将const char *转换为char_type数组;其次,使用该类在用户定义的字面值中:

#include <algorithm>

template<std::size_t N>
struct string_convert {
    char_type str[N] = {};

    consteval string_convert(const char (&s)[N]) {
        std::copy(s, s + N, str);
    }
};

template<string_convert SC>
consteval auto operator ""_s()
{
    return SC.str;
}

此接口允许以下用法:
void foo(const char_type *s);

foo("Hello, world!"_s);

在 Godbolt 上试试。请注意,无论是 string_convert 还是用户定义的文字都不会出现在反汇编中; 剩下的仅是转换后的数组。


1
太棒了!你还可以将构造函数改为 consteval string_convert(const char(&s)[N]),这样就可以省略推导指南。 - user7769147

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接