【问题标题】:How do you implement compile-time string conversion functions?你如何实现编译时字符串转换函数?
【发布时间】:2014-10-26 01:24:07
【问题描述】:

提案n4121 看起来要添加std::string_literal 类型。它包含如下代码:

template<size_t n> struct string_literal { char data [n]; }

和:

template <size_t N> 
constexpr int stoi( const string_literal<N>& str, 
                    size_t* idx = 0, int base = 10); 

这是我的 Number 类:

template <typename T>
struct Number
{
private:
    T t;
public:
    constexpr Number(const T& t)
        : t(t)
    {
    }

    constexpr Number(const std::string& s);

    constexpr operator T() const
    {
        return t;
    }
};

template <>
constexpr Number<int>::Number(const std::string& s)
    : t(std::stoi(s))
{
}

我查看了How do I convert a C string to a int at compile time?,但它仅适用于 C 字符串。并且c_str() 是非常数的。最重要的是,这不包括stolstoulstollstofstod...等等。谁知道这个提案是否会成为标准。此外,我不想等待 3 年才能发生这种库更改。我现在如何实现它?


这是我目前的尝试:

namespace lib
{
    constexpr bool is_digit(char c) {
        return c <= '9' && c >= '0';
    }

    constexpr int stoi_impl(const char* str, int value = 0) {
        return *str ?
                is_digit(*str) ?
                    stoi_impl(str + 1, (*str - '0') + value * 10)
                    : throw "compile-time-error: not a digit"
                : value;
    }

    constexpr int stoi(const char* str) {
        return stoi_impl(str);
    }

    template<size_t n> struct string_literal { char data [n]; };

    template < class charT, size_t N> 
    constexpr string_literal<N> 
        make_string_literal( const charT(&arr)[N])
        {
            string_literal<N> sl;
            for (std::size_t i = 0; i < N; ++i)
                sl.data[i] = arr[i];
            return sl;
        }
}

template <typename T>
struct Number
{
private:
    T t;
public:
    constexpr Number(const T& t)
        : t(t)
    {
    }

    constexpr Number(const std::size_t N, const lib::string_literal<N>& s);

    constexpr operator T() const
    {
        return t;
    }
};

template <>
constexpr Number<int>::Number(const std::size_t N, const lib::string_literal<N>& s)
    : t(lib::stoi(s.data))
{
}

int main()
{
    constexpr auto s = lib::make_string_literal("123456789");
    constexpr Number<int> n { sizeof(s.data), s };

    return 0;
}

main.cpp:44:69: error: non-type template argument is not a constant expression
    constexpr Number(const std::size_t N, const lib::string_literal<N>& s);
                                                                    ^
main.cpp:53:78: error: non-type template argument is not a constant expression
constexpr Number<int>::Number(const std::size_t N, const lib::string_literal<N>& s)
                                                                             ^
main.cpp:29:38: error: cannot initialize an array element of type 'char' with an lvalue of type 'const char [10]'
            return string_literal<N>{arr};
                                     ^~~
main.cpp:60:19: note: in instantiation of function template specialization 'lib::make_string_literal<char, 10>' requested here
    auto s = lib::make_string_literal("123456789");

【问题讨论】:

  • 您不能直接使用std::strings。但是,请尝试提到并链接到herestr_const 解决方案。
  • 所以问题不是根据类型选择函数,而是在编译时从字符串转换为int。我认为你的标题应该反映这一点。
  • 如果你的std::string不使用字符串文字,你是如何在编译时形成的?
  • 当你可以推断出N时,为什么要传递它? template&lt;size_t N&gt; constexpr Number(const lib::string_literal&lt;N&gt;&amp; s);?
  • 这是我不久前用 C++14 风格 constexpr 写的东西:stackoverflow.com/a/23445223

标签: c++ c++11 c++14


【解决方案1】:

我已经实现了复杂的编译时字符串到标量转换器。看看Constainer::strToFloatConstainer::strToInt

测试用例文件中的示例:

static_assert( strToInt<int>(" 6849.") == 6849 );
static_assert( strToInt<signed char>(" -128aefws") == -128 );
static_assert( strToInt<unsigned>(" \t-0") == 0 );
static_assert( strToInt<unsigned>(" -0x0Xx", 0, 0) == 0 );
static_assert( strToInt<unsigned>(" +0xFF", 0, 0) == 0xFF );
static_assert( strToInt<unsigned>(" +077", 0, 0) == 7+8*7 );
static_assert( strToInt<unsigned>("11000", 0, 2) == 24 );

/**< These should go well on most implementations. */
static_assert( strToFloat<double>("+123.456789e0") == 123.456789 );
static_assert( strToFloat<double>("-0x1.Bc70a3D70A3d7p+6") == -111.11 );
static_assert( strToFloat<double     >("-1.18973e+4932") == -std::numeric_limits<double>::infinity() );
static_assert( strToFloat<long double>("-1.18973e+4932") != -std::numeric_limits<long double>::infinity() );
static_assert( strToFloat<double>("-0x.8p-1") == -0.25 );

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-04
    • 1970-01-01
    • 2011-10-06
    • 2013-02-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多