连接一个字符串系列

时间:2017-08-25 07:37:52

标签: c++ string string-concatenation

我想编写一个函数,将std::string的任何序列与场景后面的一个malloc 连接起来。因此,需要首先计算字符串的总长度。该功能需要以这种方式使用:

std::string s0 = ...;
std::string s1 = ...;
std::string s2 = ...;

std::string s = join(s0, s1, s2);

更好的join会使用std::stringstd::string_view的混合。如果我们可以添加字符串文字会更好。你会如何在C ++ 11中编写这样的函数(它需要用gcc 4.8.5Visual Studio 2015进行编译?)

5 个答案:

答案 0 :(得分:4)

如果你有int类型,那么你可以接受string_view的集合,加上它们的大小,分配,然后复制。

string_view

答案 1 :(得分:3)

使用range-v3,您可以使用concat

const std::string s = ranges::view::concat(s0, s1, " world\n");

答案 2 :(得分:2)

这是一个可能的实现:

template<typename... Args>
std::string join(const Args&... args)
{
    size_t size = 0;
    for( const std::string& s : { args... } )
        size += s.size();

    std::string result;
    result.reserve(size);
    for( const std::string& s : { args... } )
        result += s;
    return result;
}

演示:https://wandbox.org/permlink/qwG0LMewsHwVuGXN

答案 3 :(得分:2)

Benoit几乎拥有它,他的实现只需要必要的样板来处理不同的字符串类型。值得赞扬的是,我必须承认它是相当多的锅炉板。 :)

使用gcc -std=c++17

进行编译
#include <string>
#include <string.h>
#include <string_view>
#include <iostream>

namespace detail {

    template<typename C> 
    size_t myStrLen(const std::basic_string<C>& s) { return s.length(); }

    template<typename C> 
    size_t myStrLen(const std::basic_string_view<C>& s) { return s.length(); }

    size_t myStrLen(char)    { return 1; }
    size_t myStrLen(wchar_t) { return 1; }

    size_t myStrLen(const char* s) { return strlen(s); }
    size_t myStrLen(const wchar_t* s) { return wcslen(s); }

    template<typename T, typename...Args>
    size_t myStrLen(T&& t, Args&&...args)
    {
        return myStrLen(std::forward<T>(t)) + myStrLen(args...);
    }

    template<typename C, typename T>
    void myConcat(std::basic_string<C>& result, T&& t)
    {
        result += t;
    }

    template<typename C, typename T, typename...Args>
    void myConcat(std::basic_string<C>& result, T&& t, Args&&...args)
    {
        result += t;
        myConcat(result, args...);
    }

}

template<typename C, typename... Args>
auto join(Args&&... args)
{
    std::basic_string<C> result;
    result.reserve(detail::myStrLen(args...));
    detail::myConcat(result, args...);
    return result;
}

template<typename... Args>
auto join(Args&&... args)
{
    return join<char>(args...);
}

template<typename... Args>
auto wjoin(Args&&... args)
{
    return join<wchar_t>(args...);
}

int main()
{
    std::string str{"hello"};
    std::string_view sv{"world"};

    std::wstring wstr{L"hello"};
    std::wstring_view wsv{L"world"};


    std::cout << join(str, " ", sv, '\n');
    std::wcout << wjoin(wstr, L" ", wsv, L'\n');

    return 0;
}

[编辑]将模板join<charType>移出命名空间详细信息,因为这对其他模板构造很有用。

答案 4 :(得分:1)

我相信可以使用完美转发和可变参数模板参数。

joinStr.hpp:

    class joinStr {
    public:
        template<typename... Args>
            joinStr(const std::string& first, Args&&... args): ret(""), size(0) {
                size = first.length();
                getSize((args)...);
                std::cout << "before reserve : " << ret.capacity() << std::endl;
                ret.reserve(size);
                std::cout << "after reserve : " << ret.capacity() << std::endl;
                ret.append(first);
                join(std::forward<Args>(args)...);
            }
        ~joinStr() {}
        std::string getStr() {
            std::cout << ret << std::endl;
            return ret;
        }
    private:
        std::string ret;
        int size;
        int getSize() {
            std::cout << "size : " << size << std::endl;
            return size;
        }
        template<typename... Args>
            int getSize(const std::string& first, const Args&... args) {
                size += first.length();
                return getSize((args)...);
            }
        template<typename... Args>
            int getSize(char* first, const Args&... args) {
                size += strlen(first);
                return getSize((args)...);
            }
        template<typename... Args>
            int getSize(const char* first, const Args&... args) {
                size += strlen(first);
                return getSize((args)...);
            }
        void join() {
            std::cout << "Final capacity : " << ret.capacity() << std::endl;
        }
        template<typename... Args>
            void join(const std::string& first, Args&&... args) {
                ret.append(first);
                join(std::forward<Args>(args)...);
            }
        template<typename... Args>
            void join(char* first, Args&&... args) {
                ret.append(first);
                join(std::forward<Args>(args)...);
            }
        template<typename... Args>
            void join(const char* first, Args&&... args) {
                ret.append(first);
                join(std::forward<Args>(args)...);
            }
};

主要:

int main() {
    std::string s1 = "hello";
    std::string s2 = "world !";
    std::string s3 = "meatpopsicle";
    const char* s4 = "__yeah__";
    joinStr c(s1, s2, s3, s4);
    return 1;
}

请注意,我将它包装在一个类中,但你可以在一个类之外执行相同操作。

作为奖励,它适用于std :: string,const char *和char *。

修改:修复了在getSize中重新使用移动的值,并在Caleth's建议之后为const char *添加了模板

编辑2 : 允许在const char *之后传递size_t字段而不是使用strlen的版本。

 class joinStr {
    public:
        template<typename... Args>
            joinStr(const std::string& first, Args&&... args): ret(""), size(0) {
                size = first.length();
                getSize(args...);
                std::cout << "before reserve : " << ret.capacity() << std::endl;
                ret.reserve(size);
                std::cout << "after reserve : " << ret.capacity() << std::endl;
                ret.append(first);
                join(std::forward<Args>(args)...);
            }
        ~joinStr() {}
        std::string getStr() {
            std::cout << ret << std::endl;
            return ret;
        }
    private:
        std::string ret;
        int size;
        int getSize() {
            std::cout << "size : " << size << std::endl;
            return size;
        }
        template<typename... Args>
            int getSize(const std::string& first, const Args&... args) {
                size += first.length();
                return getSize((args)...);
            }
        // const char *
        template<typename... Args, typename T>
            int getSize(const char* first, const T& t, const Args&... args) {
                getSizeImpl<T>(first, t, std::integral_constant<bool, std::is_same<T, size_t>::value>());
                return getSize(t, args...);
            }
        template<typename T>
            void getSizeImpl(const char* first, const T& t, std::false_type) {
                // Case when the next argument is not a size_t type
                size += strlen(first);
            }
        template<typename T>
            void getSizeImpl(const char* first,const T& t, std::true_type) {
                // Do nothing
            }
        template<typename... Args>
            int getSize(size_t s, const Args&... args) {
                size += s;
                std::cout << "size_t " << s << " in getSize" << std::endl;
                return getSize(args...);
            }
        void join() {
            std::cout << "Final capacity : " << ret.capacity() << std::endl;
        }
        template<typename... Args>
            void join(const std::string& first, Args&&... args) {
                ret.append(first);
                join(std::forward<Args>(args)...);
            }
        template<typename... Args>
            void join(char* first, Args&&... args) {
                ret.append(first);
                join(std::forward<Args>(args)...);
            }
        template<typename... Args>
            void join(const char* first, Args&&... args) {
                ret.append(first);
                join(std::forward<Args>(args)...);
            }
        template<typename... Args>
            void join(size_t s, Args&&... args) {
                join(std::forward<Args>(args)...);
            }
};

主要:

int main() {
    std::string s1 = "hello";
    std::string s2 = "world !";
    std::string s3 = "meatpopsicle";
    const char* s4 = "__yeah__";
    joinStr c(s1, s2, s3, s4, (size_t)8);
    return 1;
}