char数组何时是常量表达式?

时间:2019-06-25 09:53:28

标签: c++ boost template-meta-programming boost-hana

我一直在使用Boost.Hana生成编译时字符串,以用作gcc的模板参数:

using namespace boost::hana::literals;
#define GQL_STR(tok) decltype(#tok ## _s)

它依赖于设置BOOST_HANA_CONFIG_ENABLE_STRING_UDL定义集。但是我的代码应该是可移植的,并且依赖于gcc / clang扩展。阅读了出色的answer之后,我写了some code并使用Boost.Mp11对其进行了模拟,以使其更加轻松:

#include <boost/mp11/list.hpp>
#include <boost/mp11/algorithm.hpp>
#include <boost/hana/string.hpp>
#include <boost/preprocessor/config/limits.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp>

#include <iostream>

namespace
{
template <int N>
constexpr char get(const char(&str)[N], int i)
{
    return i < N ? str[i] : '\0';
}

struct is_null_char
{
    template <typename T>
    using fn = std::is_same<std::integral_constant<char, '\0'>, T>;
};

template <char... Cs>
constexpr auto list_to_string(boost::mp11::mp_list_c<char, Cs...>)
{
    return boost::hana::string<Cs...>{};
}

template <char... Cs>
struct builder
{
    using strip_null = boost::mp11::mp_remove_if_q<
        boost::mp11::mp_list_c<char, Cs...>,
        is_null_char
    >;

    using type = decltype(list_to_string(strip_null{}));
};

#define GQL_STR_CHAR(z, n, tok) \
    BOOST_PP_COMMA_IF(n) get(tok, n)

#define GQL_STR_N(n, tok) \
    typename builder<BOOST_PP_REPEAT(n, GQL_STR_CHAR, tok)>::type
}

#define GQL_STR(tok) GQL_STR_N(128, #tok)

int main()
{
    using hello_s = GQL_STR(hello);

    std::cout << hello_s{}.c_str() << std::endl;
    return EXIT_SUCCESS;
}

但是,我不喜欢强制编译器生成128个char模板参数的想法,只是在知道编译时的字符串大小时才强制它删除所有多余的参数。所以我做了一个简短的:

namespace
{
template <int N, int... I>
constexpr auto gql_str_impl(const char(&str)[N], std::integer_sequence<int, I...>)
{
    return boost::hana::string<str[I]...>{};
}

template <int N>
constexpr auto gql_str(const char(&str)[N])
{
    return gql_str_impl(str, std::make_integer_sequence<int, N-1>{});
}
}

#define GQL_STR(tok) \
    decltype(gql_str(#tok))

这不起作用。这样做的理由不充分:

<source>:15:43: error: 'str' is not a constant expression
   15 |     return boost::hana::string<str[I]...>{};

现在我不明白的是,为什么第一个代码示例完全起作用。宏扩展为:

typename builder<get("hello", 0), get("hello", 1), ...>::type

为什么str函数中的get在这里被视为常量表达式,而第二个代码示例中的 not 被视为常量表达式?

0 个答案:

没有答案