【问题标题】:Convert const char* to const char_type* at compile time在编译时将 const char* 转换为 const char_type*
【发布时间】:2020-06-23 10:34:07
【问题描述】:

考虑以下代码:

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 关键字来确保对函数的调用总是产生一个常量表达式(用户定义的文字仍然是普通函数,它们可以被调用在运行时)。知道如何实现吗?

【问题讨论】:

  • 也许使用模板代替,例如std::basic_string 可以处理不同的字符类型吗?您也可以采用 Microsoft 的方式并使用宏为所有字符串文字自动添加合适的前缀,例如#define T(s) L ## s 或类似名称,然后使用 foo(T("Hello world"))
  • std::basic_string<T>不能转换成std::basic_string<U>是T和U不相等,而且编译时不能使用。我从来没有听说过这种微软方式,它是如何工作的?
  • 指针需要内存指向。 consteval 函数不能神奇地凭空产生内存。
  • @n。 '代词' m。例如,实际上使用模板可以在编译时连接字符串。 this answer 到另一篇文章解释了如何做到这一点,即使它只适用于 std::string_view 的左值
  • 嗯,看起来需要非类型模板参数,但尚未在所有地方实现。

标签: c++ type-conversion c++20 user-defined-literals


【解决方案1】:

这种转换可以通过两个步骤进行:首先,通过在编译时构造函数中声明一个可以将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);

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

【讨论】:

  • 很棒的解决方案!也可以把构造函数改成consteval string_convert(const char(&amp;s)[N]),这样就可以省略推导指南了