首页 > 解决方案 > 从某个字符串文字和一个 int 模板参数的串联创建一个 constexpr C 字符串

问题描述

我有一个带有 int 模板参数的类。在某些情况下,我希望它输出错误消息。此消息应该是一些固定文本和模板参数的串联字符串。出于性能原因,我想避免在每次发生错误时在运行时构建这个字符串,理论上,字符串文字和模板参数在编译时都是已知的。所以我正在寻找一种可能性将其声明为 constexpr。

代码示例:

template<int size>
class MyClass
{
    void onError()
    {
        // obviously won't work but expressing the concatenation like
        // it would be done with a std::string for clarification 
        constexpr char errMsg[] = "Error in MyClass of size " + std::to_string (size) + ": Detailed error description\n";

        outputErrorMessage (errMsg);
    }
}

标签: c++stringconstexpr

解决方案


使用static const将只允许计算一次(但在运行时):

template<int size>
class MyClass
{
    void onError()
    {
        static const std::string = "Error in MyClass of size "
                                  + std::to_string(size)
                                  + ": Detailed error description\n";

        outputErrorMessage(errMsg);
    }
};

如果您真的想在编译时拥有该字符串,您可以使用std::array,例如:

template <std::size_t N>
constexpr std::size_t count_digit() {
    if (N == 0) {
        return 1;   
    }
    std::size_t res = 0;
    for (int i = N; i; i /= 10) {
        ++res;
    }
    return res;
}

template <std::size_t N>
constexpr auto to_char_array()
{
    constexpr auto digit_count = count_digit<N>();
    std::array<char, digit_count> res{};

    auto n = N;
    for (std::size_t i = 0; i != digit_count; ++i) {
        res[digit_count - 1 - i] = static_cast<char>('0' + n % 10);
        n /= 10;
    }
    return res;
}

template <std::size_t N>
constexpr std::array<char, N - 1> to_array(const char (&a)[N])
{
    std::array<char, N - 1> res{};

    for (std::size_t i = 0; i != N - 1; ++i) {
        res[i] = a[i];
    }
    return res;
}

template <std::size_t ...Ns>
constexpr std::array<char, (Ns + ...)> concat(const std::array<char, Ns>&... as)
{
    std::array<char, (Ns + ...)> res{};
    std::size_t i = 0;
    auto l = [&](const auto& a) { for (auto c : a) {res[i++] = c;} };

    (l(as), ...);
    return res;
}

最后:

template<int size>
class MyClass
{
public:
    void onError()
    {
        constexpr auto errMsg = concat(to_array("Error in MyClass of size "),
                                  to_char_array<size>(),
                                  to_array(": Detailed error description\n"),
                                  std::array<char, 1>{{0}});

        std::cout << errMsg.data();
    }
};

演示


推荐阅读