我想实现一个以std::vector
或std::array
作为参数的函数。参数列表如何从容器类型中抽象出来?
请参见以下示例:
// how to implement this?
bool checkUniformity(container_type container)
{
for(size_t i = 1; i < container.size(); i++)
{
const auto& o1 = container[i-1];
const auto& o2 = container[i];
if(!o1.isUniform(o2))
return false;
}
return true;
}
struct Foo
{
bool isUniform(const Foo& other);
}
// I want to call it in both ways:
std::vector<Foo> vec;
std::array<Foo> arr;
bool b1 = checkUniformity(vec);
bool b2 = checkUniformity(arr);
做到这一点的最好,最易读的方法是什么?
也欢迎任何有关代码改进(样式,设计)的建议。谢谢!
答案 0 :(得分:6)
您要template
:
template <typename container_type>
bool checkUniformity(const container_type& container)
{
for(size_t i = 1; i < container.size(); i++)
{
const auto& o1 = container[i-1];
const auto& o2 = container[i];
if(!o1.isUniform(o2))
return false;
}
return true;
}
答案 1 :(得分:4)
接受几乎所有容器类型是将模板与模板模板参数一起使用的一个好主意。 C ++中的大多数容器都将它们所拥有的值类型以及用于分配内存的分配器类型接受为第一模板参数。
要检查容器的值类型是否实现了特定的方法isUniform()
,可以使用std::enable_if
。
#include <iostream>
#include <vector>
#include <type_traits>
struct Foo
{
bool isUniform(const Foo&) const { return true; }
};
//Template template parameter TContainer, that accepts 2 template parameters
//the first for the value_type, the second for the allocator type
template <template <typename, typename> typename TContainer, typename TValue, typename TAllocator>
auto checkUniformity(TContainer<TValue, TAllocator>& container)
//Using `std::enable_if` to check if the result of invoking the `isUniform()` method is bool
//in case it is not bool, or the method does not exist, the `std::enable_if_t` will result
//in an error
-> std::enable_if_t
<
std::is_same_v
<
decltype(std::declval<TValue>().isUniform(std::declval<TValue>())),
bool
>,
bool
>
{
for(size_t i = 1; i < container.size(); i++)
{
const auto& o1 = container[i-1];
const auto& o2 = container[i];
if(!o1.isUniform(o2))
return false;
}
return true;
}
int main()
{
std::vector<Foo> vec(10);
std::cout << std::boolalpha << checkUniformity(vec);
return 0;
}
请注意,std::array
没有分配器类型,因此此方法不适用于std::array
。
为此,您可以将TContainer
更改为简单的模板类型参数,并在需要使用typename TContainer::value_type
的任何地方使用TValue
。
答案 2 :(得分:4)
如果您使用迭代器和范围而不是直接使用容器,则可以生成一种算法,该算法可以有效地使用任何容器(包括链接列表)以及流:
var myNodelist = document.querySelectorAll("a");
var URLList = [];
for (var i = 0; i < myNodelist.length; i++) {
if (myNodelist[i].href) {
URLList.push(myNodelist[i].href);
}
}
console.log(URLList)
您还可以实现如图所示的第二种变体,如果您有#include <list>
#include <array>
#include <vector>
#include <iterator>
template <typename T>
bool checkUniformity(T begin, T end) {
// Check for empty range
if (begin == end) return true;
// Remember last element
T last = begin;
while (++begin != end) {
if (!((*last).isUniform(*begin)))
return false;
last = begin;
}
return true;
}
template <typename T, typename F>
bool checkUniformity(T begin, T end, F pred) {
// Check for empty range
if (begin == end) return true;
// Remember last element
T last = begin;
while (++begin != end) {
if (!pred(*last, *begin))
return false;
last = begin;
}
return true;
}
struct Foo
{
bool isUniform(const Foo& other) const;
};
int main () {
// I want to call it in both ways:
std::vector<Foo> vec;
std::array<Foo, 3> arr;
std::list<Foo> list;
Foo carr [3];
bool b1 = checkUniformity(std::cbegin(vec), std::cend(vec));
bool b2 = checkUniformity(std::cbegin(arr), std::cend(arr));
bool b3 = checkUniformity(std::cbegin(list), std::cend(list));
bool b4 = checkUniformity(std::cbegin(carr), std::cend(carr));
bool b1_2 = checkUniformity(std::cbegin(vec), std::cend(vec), [] (const Foo& a, const Foo& b) { return a.isUniform(b); });
bool b2_2 = checkUniformity(std::cbegin(arr), std::cend(arr), [] (const Foo& a, const Foo& b) { return a.isUniform(b); });
bool b3_2 = checkUniformity(std::cbegin(list), std::cend(list), [] (const Foo& a, const Foo& b) { return a.isUniform(b); });
bool b4_2 = checkUniformity(std::cbegin(carr), std::cend(carr), [] (const Foo& a, const Foo& b) { return a.isUniform(b); });
}
的不同变体,则可以在其中将条件指定为谓词(例如,lambda,如图所示)。必须为范围传递两个参数,而不仅仅是传递容器,这稍微麻烦一些,但更加灵活。它还允许您在容器的子范围内运行算法。
这与标准库算法(例如isUniform
)所使用的方法相同。
答案 3 :(得分:0)
U也可以执行函数重载,以防万一您不想使用模板。