2

现在,我使用的函数'JoinStrings'只能加入数据类型std::string。我现在需要加入整数。所以我希望重构它。但我失败了。我很高兴听到“你不能这样做”,因为我真的不知道以这种方式重用这些代码是否合理。

调用部分:

int main(int argc, char* argv[]) {
      vector<int> integers;
      string str = JoinStrings(integers);
      cout << str << endl;
}

我未能实施的部分:

#include <string>

template <class ConstForwardIterator>
void JoinStrings(const ConstForwardIterator& begin,
                 const ConstForwardIterator& end,
                 const std::string& delimiter,
                 std::string* output) {
  output->clear();
  for (ConstForwardIterator iter = begin; iter != end; ++iter) {
    if (iter != begin) {
      output->append(delimiter);
    }   
    output->append(*iter);
  }
}

// What data type should be declared for IntegerConstForwardIterator?
template<>
void JoinStrings(const IntegerConstForwardIterator& begin,
                 const IntegerConstForwardIterator& end,
                 const std::string& delimiter,
                 std::string* output) {
  output->clear();
  for (IntegerConstForwardIterator iter = begin; iter != end; ++iter) {
    if (iter != begin) {
      output->append(delimiter);
    }   
    output->append(std::to_string(*iter));
  }
}

template <class ConstForwardIterator>
std::string JoinStrings(const ConstForwardIterator& begin,
                        const ConstForwardIterator& end,
                        const std::string& delimiter) {
  std::string output;
  JoinStrings(begin, end, delimiter, &output);
  return output;
}

template <class Container>
std::string JoinStrings(const Container& container,
                        const std::string& delimiter = " ") {
  return JoinStrings(container.begin(), container.end(), delimiter);
}
4

2 回答 2

0

可以修改代码以实现您想要的。我将此问题解释为模板专业化练习。(对于推荐的替代方案,请遵循 jogojapan 的评论)

前言:我期待它能够工作,但是(尽管它可以编译)它并没有因为通用版本仍然是一个更好的匹配:

template<template <class> class Cont >
void JoinStrings(const typename Cont<int>::const_iterator& begin,
                 const typename Cont<int>::const_iterator& end,
                 const std::string& delimiter,
                 std::string* output) {
    std::clog << "specialized called" << std::endl;
    ....
}

所以,我只好求助于旧的enable_if(为了简洁起见,我在这里使用 c++11,可以在 C++98 中做出一些努力)。使用您的main代码将调用专用版本。

解决方案

#include<type_traits>
....
template <class ConstForwardIterator, 
    class = typename std::enable_if<not std::is_same<typename std::decay<decltype(*std::declval<ConstForwardIterator>())>::type, int>::value>::type
>
void JoinStrings(const ConstForwardIterator& begin,
                 const ConstForwardIterator& end,
                 const std::string& delimiter,
                 std::string* output) {
    std::clog << "generic called" << std::endl;
    std::clog << std::trace() << std::endl;
}

template <class ConstForwardIterator, 
    class = typename std::enable_if<std::is_same<typename std::decay<decltype(*std::declval<ConstForwardIterator>())>::type, int>::value>::type,
    class Tag = void
>
void JoinStrings(const ConstForwardIterator& begin,
                 const ConstForwardIterator& end,
                 const std::string& delimiter,
                 std::string* output) {
    std::clog << "special called" << std::endl;
    ....
}

一个更经典的解决方案是使用“标签调度” http://www.boost.org/community/generic_programming.html#tag_dispatching,但这需要更改更多代码,例如您的容器版本的 JoinString。

受限解决方案:如果您希望代码仅适用std::vector于解决方案,则要简单得多:

template <>
void JoinStrings(const std::vector<int>::const_iterator& begin,
                 const std::vector<int>::const_iterator& end,
                 const std::string& delimiter,
                 std::string* output)
于 2013-06-24T04:30:16.607 回答
0

这是你想要的吗?正如@jogojapan 所说,使用 std::ostringstream 是一个更好的选择。

#include <vector>
#include <string>
#include <iostream>
#include <sstream>

template <class ConstForwardIterator>
std::string JoinStrings(const ConstForwardIterator& begin,
        const ConstForwardIterator& end,
        const std::string& delimiter) {
    std::ostringstream oss;
    for (ConstForwardIterator iter = begin; iter != end; ++iter) {
        if (iter != begin) {
            oss << delimiter;
        }
        oss << *iter;
    }
    return oss.str();
}

template <class Container>
std::string JoinStrings(const Container &container,
        const std::string& delimiter = " ") {
    return JoinStrings(container.begin(),
            container.end(), delimiter);
}

int main(int argc, char *argv[]) {
    std::vector<int> integers;
    integers.push_back(1);
    integers.push_back(2);
    integers.push_back(3);
    std::string str = JoinStrings(integers);
    std::cout << str << std::endl;

    std::vector<std::string> strings;
    strings.push_back("MOU");
    strings.push_back("BI");
    str = JoinStrings(strings);
    std::cout << str << std::endl;
    return 0;
}
于 2013-06-27T02:33:44.437 回答