将元组转换为字符串

4
自从我发现了 boost::lexical_cast 后,所有的类型转换都变得轻而易举。但当我尝试将元组元素转换为字符串时,情况就不同了。与 Int2StringDouble2String 类似,我想要一种从任意数量元素的元组生成单个字符串的方法。
由于转换对象具有任意(但在编译时已知)维度,经过了一些研究后,我查阅了boost::fusion并找到了这个解决方案:
#include <string>
#include <boost/lexical_cast.hpp>
#include <boost/noncopyable.hpp>
#include <boost/fusion/include/for_each.hpp>

template <class Sequence>
std::string StringFromSequence(const Sequence &seq) 
{
    std::string result;
    boost::fusion::for_each(seq, toString(result));
    return result;
}

其中toString是一个函数对象,将被调用的对象应用于词法转换:

struct toString: boost::noncopyable 
{
    explicit toString(std::string& res) : result(res)
    {
    }
    template <class T>
    void operator()(const T& v) 
    {
        result += boost::lexical_cast<std::string>(v);
    }
private:
    std::string &result;
};

尝试使用时:
std::tuple<int, char, double> tup{ 1, 'a', 2.2 };
toString(tup);

我遇到了编译错误。

错误 C2893: 无法特化函数模板 'enable_if, void>::type boost::fusion::for_each(const Sequence &,const F &)'

  1. 有人能找出并纠正这个错误吗?
  2. 是否有任何(可能是不使用boost的)替代方案?(这将需要编译时递归,而我希望尽可能避免所有那些样板代码)
2个回答

3

由于这个问题被标记为C++11,以下是我的看法:

#include <iostream>
#include <string>
#include <tuple>

template<typename T, T...>
struct integer_sequence { };

template<std::size_t N, std::size_t... I>
struct gen_indices : gen_indices<(N - 1), (N - 1), I...> { };
template<std::size_t... I>
struct gen_indices<0, I...> : integer_sequence<std::size_t, I...> { };

template<typename H>
std::string& to_string_impl(std::string& s, H&& h)
{
  using std::to_string;
  s += to_string(std::forward<H>(h));
  return s;
}

template<typename H, typename... T>
std::string& to_string_impl(std::string& s, H&& h, T&&... t)
{
  using std::to_string;
  s += to_string(std::forward<H>(h));
  return to_string_impl(s, std::forward<T>(t)...);
}

template<typename... T, std::size_t... I>
std::string to_string(const std::tuple<T...>& tup, integer_sequence<std::size_t, I...>)
{
  std::string result;
  int ctx[] = { (to_string_impl(result, std::get<I>(tup)...), 0), 0 };
  (void)ctx;
  return result;
}

template<typename... T>
std::string to_string(const std::tuple<T...>& tup)
{
  return to_string(tup, gen_indices<sizeof...(T)>{});
}

int main(int argc, char** argv)
{
  std::tuple<int, double, float> tup(1, 2.1, 3.2);
  std::cout << to_string(tup) << std::endl;
}

如果您想继续使用boost::lexical_cast,请用lexical_cast替换to_string。
ideone上实时输出。

当我的元组中有一个 std::string 时,我会得到这个错误:error: no matching function for call to ‘to_string(const std::__cxx11::basic_string<char>&)’ s += to_string(std::forward<H>(h)); 有什么想法如何解决它吗? - ph_0

3

抱歉,我懒得详细说明你在哪里犯了错误,但是这里有一个使用融合和C++14多态lambda的解决方案:

#include <tuple>
#include <string>
#include <iostream>
#include <boost/lexical_cast.hpp>
#include <boost/fusion/adapted/std_tuple.hpp> // you're missing this huh? it's needed to use fusion with std::tuple
#include <boost/fusion/algorithm/iteration/for_each.hpp>

int main() {
    using namespace std;
    using namespace boost::fusion;

    string result;
    for_each(make_tuple(1, 'a', 2.2), [&result](auto &s) {
        result += boost::lexical_cast<string>(s) + ' ';
    });

    cout << result << endl;
}

http://coliru.stacked-crooked.com/a/f110238a317eede9


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接