2016-11-17 86 views
6

作为一个练习,我试图在C++中实现Pythons join()方法。我最终将该功能作为std::string类的一种方法添加,但我认为让它起作用更重要。我已经定义了如下函数:C++:如何通过任何可迭代类型作为函数参数

template<typename Iterable> 
std::string join(const std::string sep, Iterable iter); 

有什么办法可以确保Iterable类型实际上是可迭代的吗?例如。我不希望收到intchar ..

感谢您的帮助

+2

你如何定义“迭代”? – Galik

+0

@Galik我将它定义为容器,你可以迭代通过 – aydow

+0

你能提供一个真实的例子显示你将如何调用这个函数? – Galik

回答

5

在C++中,而不是一个Iterable,我们传递一个迭代器(几乎指针)的前部和结束范围:

template<typename Iter> 
std::string join(const std::string &sep, Iter begin, Iter end); 

注意,sep应该为const 参考传递,因为你并不需要复制。

不过你不需要担心Iter是否实际上是一个迭代器。这是因为如果代码不起作用,代码将无法编译。

例如,假设你实现它像这样(这是一个糟糕的实现):

template<typename Iter> 
std::string join(const std::string &sep, Iter begin, Iter end) { 
    std::string result; 

    while (begin != end) { 
     result += *begin; 
     ++begin; 
     if (begin != end) result += sep; 
    } 

    return result; 
} 

然后传递进来Iter类型必须有一个operator++,一个operator!=operator*工作,这是一个迭代器很好理解的合约。

+1

“(几乎是一个指针)”..在技术上它可以是一个指针,例如, 'char * x =“hello”;加入(“”,x,x + 5);' – txtechhelp

+0

已经发生在我身上,但pythons的语法是''string“.join(list)'所以我试图模仿它。我不知道它也与C++风格 – aydow

+0

冲突,你能解释为什么它是一个糟糕的实现吗? – aydow

1

所有标准C++集合都有begin()end()成员函数。你可以利用这一事实,以确保传递的参数实际上是一个集合(在您的术语 - 迭代器)一些SFINAE(C++ 11例):

#include <array> 
#include <list> 
#include <vector> 
#include <map> 
#include <string> 

template <class Iterable> 
auto join(const std::string sep, const Iterable& iterable) -> decltype(iterable.begin(), iterable.end(), std::string{}) { 
    (void)sep; // to suppress warning that sep isn't used 
    // some implementation 
    return {}; 
} 

int main() { 
    join(";", std::array<int, 5>{}); 
    join(";", std::list<int>{}); 
    join(";", std::vector<float>{}); 
    join(";", std::string{}); 
    join(";", std::map<int, float>{}); 
    //join(";", int{}); // does not compile as int is not a collection 
} 

[live demo]

相关问题