如何正确解析const std :: string&amp;和const std :: vector <string>&amp;模糊?

时间:2016-02-15 18:39:12

标签: c++ c++11 overloading

我有一个函数,我有这样的重载:

void process(const std::string& text)
{
}

void process(const std::vector<std::string>& manyTexts)
{
}

我称之为:

process({"hello", "hey"});

我希望这可以解决第二次重载,但这显然是模棱两可的。令我惊讶的是我发现这个要编译:

std::string text = {"hello", "hey"};

变量只包含&#39;你好&#39;这似乎没有用,也不直观。

有了这个,我有两个问题:

  1. 是什么导致它成为std::string的有效初始化程序?
  2. 这可以通过某种方式解决,不涉及重命名功能或避免使用初始化列表吗?

2 个答案:

答案 0 :(得分:5)

std::string有一个构造函数:

template< class InputIt >
basic_string( InputIt first, InputIt last, 
              const Allocator& alloc = Allocator() );

电话

std::string text = {"hello", "hey"};

解析为该构造函数。即使语法上调用解析为有效的构造函数,这也会导致运行时的未定义行为,因为"hello""hey"是不相关的字符串。

制作

的唯一方法
process({"hello", "hey"});

解决第二个功能就是明确它。

process(std::vector<std::string>{"hello", "hey"});

答案 1 :(得分:1)

我回来了。我没有解决您的问题,而是暴露了process( std::experimental::span<const std::string> )重载。

请参阅std::experimental::array_view,其中较弱的版本易于编写。

大部分工作都在你想要的长长的名单中:

template<class T>
struct span {
  T* b = nullptr;
  T* e = nullptr;
  T* begin() const { return b; }
  T* end() const { return e; }
  bool empty() const { return begin()==end(); }
  std::size_t size() const { return end()-begin(); }
  T& front() const { return *begin(); }
  T& back() const { return *std::prev(end()); }

  // extra useful things I have added in my version:
  span without_front(std::size_t N=1) const {
    return {begin()+(std::min)(size(), N), end()};
  }
  span without_back(std::size_t N=1) const {
    return {begin(), end()-(std::min)(size(), N)};
  }

  // ctors: span uses "pointer semantics":
  span()=default;
  span(span const&)=default;
  span& operator=(span const&)=default;
  ~span()=default;
  // useful ctors for making a span:
  span( T* s, T* f ):b(s), e(f) {}
  span( T* s, std::size_t len ):span(s, s+len) {}

  using non_const_T = std::remove_const_t<T>;

  template<class A>
  span( std::vector<T, A>& in ):span(in.data(), in.size()) {}
  template<class A>
  span( std::vector<non_const_T, A> const& in ):span(in.data(), in.size()) {}
  template<class Traits>
  span( std::string<T, Traits>& in ):span(in.data(), in.size()) {}
  template<class Traits>
  span( std::string<non_const_T, Traits> const& in ):span(in.data(), in.size()) {}
  template<std::size_t N>
  span( std::array<T, N>& in ):span(in.data(), in.size()) {}
  template<std::size_t N>
  span( std::array<non_const_T, N>const& in ):span(in.data(), in.size()) {}
  template<std::size_t N>
  span( T(&in)[N] ):span(in.data(), in.size()) {}
  span( std::initializer_list<non_const_T> in ):span(in.begin(), in.size()) {}
};

这消除了vector实施中不必要的分配。

这使得单字符串版本毫无意义。

void process(span<const std::string> texts)
{
   for (const std::string& text:texts) {
     // process one element
   }
}

使用字符串调用,执行process({"bob"})。对于字符串s,请执行process({s})。要使用向量v进行调用,请执行process(v)

工业品质span只有process(non_const_T)的{​​{1}}样式构造函数,但我很懒惰。