Sprout を使った constexpr stringstream

ちょっと欲しかったので簡単に書いてみました。


[ソース]

#include <sprout/string.hpp>
#include <sprout/operation.hpp>


template<std::size_t Size, typename String = sprout::string<Size>>
struct basic_stringstream{
    constexpr String const&
    str() const{
        return string;
    }

    String string;
};


typedef basic_stringstream<0> stringstream;

template<std::size_t Lim>
using stringstream_lim = basic_stringstream<Lim>;


template<
    std::size_t N, typename String,
    typename Output,
    typename Result = basic_stringstream<N, String>
>
constexpr Result
output(basic_stringstream<N, String> const& ss, Output const& output){
    return Result{ sprout::realign_to<String>(ss.str() + output) };
}


template<typename String, typename Output>
constexpr auto
output(basic_stringstream<0, String> const& ss, Output const& output)
->basic_stringstream<0, decltype(String{} + output)>{
    return basic_stringstream<0, decltype(String{} + output)>{ ss.str() + output };
}


template<std::size_t Size, typename String, typename T, std::size_t N>
constexpr auto
operator <<(basic_stringstream<Size, String> const& ss, T const(&str)[N])
->decltype(output(ss, sprout::to_string(str))){
    return output(ss, sprout::to_string(str));
}

template<
    std::size_t Size, typename String, typename Source,
    typename = typename std::enable_if<sprout::is_string<Source>{}>::type
>
constexpr auto
operator <<(basic_stringstream<Size, String> const& ss, Source const& str)
->decltype(output(ss, str)){
    return output(ss, str);
}

template<std::size_t Size, typename String, typename Source>
constexpr auto
operator <<(basic_stringstream<Size, String> const& ss, Source const& str)
->decltype(output(ss, sprout::to_string(str))){
    return output(ss, sprout::to_string(str));
}


int
main(){
    {
        constexpr stringstream_lim<16> ss{};
        constexpr auto result = ss << "homu";
        static_assert(result.str() == "homu", "");

        constexpr auto result2 = result << "mado";
        static_assert(result2.str() == "homumado", "");
    }

    {
        constexpr stringstream_lim<16> ss{};
        constexpr auto result = ss << "homu" << "mado";
        static_assert(result.str() == "homumado", "");
    }

    {
        constexpr stringstream_lim<4> ss{};
        constexpr auto result = ss << "homuhomu";
        static_assert(result.str() == "homu", "");
    }

    {
        constexpr stringstream_lim<4> ss{};
        constexpr auto result = ss << "homuhomu";

        constexpr sprout::string<4> str = result.str();
        static_assert(str == "homu", "");
    }

    {
        constexpr stringstream ss{};
        constexpr auto result = ss << "homuhomu";
        static_assert(result.str() == "homuhomu", "");
    }

    {
        constexpr stringstream ss{};
        constexpr auto result = ss << "homuhomu" << "madomado";
        static_assert(result.str() == "homuhomumadomado", "");
    }

    {
        constexpr stringstream ss{};
        constexpr auto result = ss << 1234;
        static_assert(result.str() == "1234", "");
    }

    {
        constexpr stringstream ss{};
        constexpr auto result = ss << 3.14f;
        static_assert(result.str() == "3.140000", "");
    }

    {
        constexpr stringstream ss{};
        constexpr auto result = ss << 1234 << ":" << 3.14f << ":" << sprout::to_string("homu");
        static_assert(result.str() == "1234:3.140000:homu", "");
    }

    return 0;
}

とりあえず、固定長のバッファと可変長のバッファが欲しかったので、ちょっと処理を分けてみました。
基本的には可変長のバッファで問題無いと思いますが、関数の戻り値型として使用するのであれば固定長のバッファの方がいいかなー。

[コンパイラ]

  • g++ (GCC) 4.7.0 20120218 (experimental)