2014-10-26 27 views
5

Teklif n4121 bir std::string_literal türünü ekleyecektir. BuradaDerleme zamanı dize dönüştürme işlevlerini nasıl uygularsınız?

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

Ve Numara sınıfı var:

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

ve: Bu gibi kod içeren ben How do I convert a C string to a int at compile time? bir göz atmış

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)) 
{ 
} 

ancak yalnızca C dizeleri çalışır. ve c_str(), non-constexpr'dir. Bunun da ötesinde, bu, stol, stoul, stoll, stof, stod ... ve diğerlerini kapsamaz. Bu teklifin standart haline getirip getirmeyeceğini kim bilir. Ayrıca bu kütüphane değişimi için 3 yıl beklemek istemiyorum. Şimdi bunu nasıl uygularım? Ben sayıl dönüştürücüler için gelişmiş derleme zamanı dize uyguladık

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"); 
+1

doğrudan 'std :: string's kullanamaz. Bununla birlikte, belirtilen [str_const] çözümünü deneyin ve burada [http://stackoverflow.com/questions/15858141/conveniently-declaring-compile-time-strings-in-c] bağlantısını tıklayın. – Pradhan

+0

Bu nedenle sorun, türe göre bir işlev seçmemek değil, derleme zamanında dizeden int'ye dönüştürmektir. Sanırım başlığınız bunu yansıtmalı. – jogojapan

+0

Bir dize değişmezi kullanmıyorsa, std :: string 'nizi derleme zamanında nasıl oluşturdunuz? – jxh

cevap

1

:


İşte şimdiye kadar benim denemesi. Constainer::strToFloat ve Constainer::strToInt'a bir göz atın. testcase dosyasından

Örnekler:

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);