编译时来自字符串的 Char 序列,无需递归

Char sequence from string at compile time WITHOUT recursion

是的,这个话题可能看起来已经被问了一百遍了,但我问的是非常不同的。

请不要让我误解:模板递归在 C++03 中使用时可能很棒,并且是某些习语的唯一方法,但在 MSVS 2017/2019 编译器中使用并获取时可能会出现问题可怕的fatal error C1202: recursive type or function dependency context too complex.

我知道 gcc 和 clang 管理的递归比 MSVS 好得多,但是这次编译器是一个合同主题,不能更改。

我开始使用 boost::hana::string,但是对于复杂的字符串(超过 2000 个字符)会出现错误。

我想知道是否有某种方法可以复制 BOOST_HANA_STRING 宏的行为(基本上它接受一个字符串并将其转换为 char 序列,或 wchar 取决于输入字符串)但摆脱递归。

我想付出的代价是完全使用 C++17,而不是使用 fold,但对我来说这是负担得起的。

顺便说一句,请不要提供operator""_cs解决方案,因为MSVS不兼容这样的gcc扩展。

我想要实现的伪代码:

STRING("Hello") => my_static_string<char, 'H', 'e', 'l', 'l', 'o'>

I wonder if there is some way to replicate the behaviour of BOOST_HANA_STRING macro (basically it takes a string and converts it into a char sequence, or wchar depending of input string) but getting rid of recursion.

好吧,这会很困难,因为 BOOST_HANA_STRING doesn't use recursion:

    namespace string_detail {
        template <typename S, std::size_t ...N>
        constexpr string<S::get()[N]...>
        prepare_impl(S, std::index_sequence<N...>)
        { return {}; }

        template <typename S>
        constexpr decltype(auto) prepare(S s) {
            return prepare_impl(s,
                std::make_index_sequence<sizeof(S::get()) - 1>{});
        }
    }

#define BOOST_HANA_STRING(s)                                                \
    (::boost::hana::string_detail::prepare([]{                              \
        struct tmp {                                                        \
            static constexpr decltype(auto) get() { return s; }             \
        };                                                                  \
        return tmp{};                                                       \
    }()))                                                                   \

注意缺少递归。它只是获取字符串的大小,使用它来构建索引序列,并使用该序列来构建字符串元素的包扩展。它总是恰好是 2 个函数调用深度;不多也不少

你的问题不是递归;您的问题是 Visual Studio 不支持“2000”元素参数包。 C++ 标准只建议编译器支持 1024 个模板参数,Visual C++ support 2046。我不会指望这个数字在未来变得更大,所以你需要找到替代方法来做你在这里做的任何事情。

此外,C++20 允许您创建一个真正的编译时字符串 class,它存储实际字符的实际数组,您可以在正常的实际代码中实际使用这些实际字符,而不是元编程。并且它们可以用作模板参数;一个 单个 模板参数。 VC++ 已经支持这个。