[英]C++ Interfacing queue or priority_queue as template parameter of a class
I have a class (named Banana
in the example) that would receive as a template argument (named Q
in the example) a std::queue
or a std::priority_queue
. 我有一个类(在示例中名为Banana
),它将作为模板参数(在示例中名为Q
)接收std::queue
或std::priority_queue
。 The only methods that are required for this argument are push()
, pop()
and front()
. 此参数所需的唯一方法是push()
, pop()
和front()
。 Now the problem: both queues have push()
and pop()
, but the front()
method in the std::priority_queue
(the equivalent one) is named top()
. 现在问题是:两个队列都有push()
和pop()
,但是std::priority_queue
(等效的)中的front()
方法名为top()
。 How can I interface this parameter Q
? 如何连接此参数Q
?
I'm thinking about different solutions, but none of these convinces me. 我正在考虑不同的解决方案,但这些解决方案都没有让我信服。 I'm writing a C++ library and I don't want dirty solutions that would complicate the life of the library user. 我正在编写一个C ++库,我不想要那些会使库用户的生活变得复杂的脏解决方案。 Here is what I've thought: 这是我的想法:
std::priority_queue
that implements front()
method. 创建一个实现front()
方法的std::priority_queue
子类。 That's dirty. 那很脏。 Add another template argument that accepts a function like: 添加另一个接受以下函数的模板参数:
[] (const std::priority_queue& q) { q.top(); }
or 要么
[] (const std::queue& q) { q.front(); }
depending on the used queue type. 取决于使用的队列类型。 Dirty: complicates life to the library user. 脏:使图书馆用户的生活变得复杂。
Do you have one that's simple and elegant? 你有一个简单而优雅的吗?
#include <iostream>
#include <queue>
#include <utility>
template <typename T, class Q = std::queue<T>>
class Banana
{
private:
Q queue;
public:
void push(T&& o)
{
queue.push(std::move(o));
}
const T& top()
{
return queue.front();
}
};
int main()
{
Banana<int> banana0;
banana0.push(0);
std::cout << banana0.top() << std::endl;
Banana<int, std::priority_queue<int>> banana1;
banana1.push(1);
std::cout << banana1.top() << std::endl;
return 0;
}
Obviously this won't compile. 显然这不会编译。 But I'm posting the compiler response to explain better the problem: 但我发布了编译器响应以更好地解释问题:
test.cxx: In instantiation of ‘const T& Banana<T, Q>::top() [with T = int; Q = std::priority_queue<int>]’:
test.cxx:32:34: required from here
test.cxx:20:30: error: ‘class std::priority_queue<int>’ has no member named ‘front’
return queue.front();
This is only a simplified example. 这只是一个简化的例子。 The real problem is much more complex. 真正的问题要复杂得多。
You might use the SFINAE way, something like: 您可以使用SFINAE方式,例如:
template <typename T, class Q = std::queue<T>>
class Banana
{
private:
Q queue;
template <typename Queue>
static
auto private_top(Queue& queue) -> decltype(queue.top()) { return queue.top();}
template <typename Queue>
static
auto private_top(Queue& queue) -> decltype(queue.front()) { return queue.front();}
public:
void push(T&& o)
{
queue.push(std::move(o));
}
const T& top()
{
return private_top(queue);
}
};
Add a level of indirection: 添加间接级别:
template<typename T, class C>
auto& front_or_top(std::queue<T, C> const &q) {
return q.front();
}
template<typename T, class C, typename Comp>
auto& front_or_top(std::priority_queue<T, C, Comp> const &q) {
return q.top();
}
And let overload resolution do its thing. 并让重载解决方案做到了。
I don't know if it make sense but with C++17 you could use std::experimental::is_detected
like following: 我不知道它是否有意义但是使用C ++ 17你可以使用std::experimental::is_detected
如下:
#include <iostream>
#include <queue>
#include <set>
#include <experimental/type_traits>
template<typename T>
using front_t = decltype( std::declval<T&>().front() );
template<typename T>
constexpr bool has_front = std::experimental::is_detected_v<front_t, T >;
template<class T>
void elementTop(T& obj)
{
if constexpr (has_front<T>)
{
obj.front();
std::cout << "Front \n";
}
else
{
obj.top();
std::cout << "Top \n";
}
}
int main()
{
std::priority_queue<int> q1;
std::queue<int> q2;
std::vector<int> vec;
std::set<int> s;
elementTop(q1) ;
elementTop(q2) ;
elementTop(vec) ;
/* elementTop(s) ; errors out */
return 0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.