C++接口队列或priority_queue作为类的模板参数
C++ Interfacing queue or priority_queue as template parameter of a class
说明
我有一个类(在本例中名为Banana
),它将接收std::queue
或std::priority_queue
作为模板参数(在本示例中名为Q
)。此参数唯一需要的方法是push()
、pop()
和front()
。现在的问题是:两个队列都有push()
和pop()
,但std::priority_queue
中的front()
方法(等效方法)被命名为top()
。如何接口此参数Q
?
可能的解决方案
我正在考虑不同的解决方案,但没有一个能让我信服。我正在写一个C++库,我不希望肮脏的解决方案会使库用户的生活复杂化。以下是我的想法:
- 创建一个实现
front()
方法的std::priority_queue
的子类。太脏了 -
添加另一个接受以下函数的模板参数:
[] (const std::priority_queue& q) { q.top(); }
或
[] (const std::queue& q) { q.front(); }
取决于所使用的队列类型。肮脏:使图书馆用户的生活变得复杂。
你有简单优雅的吗?
示例
#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;
}
显然这不会编译。但我发布编译器的回应是为了更好地解释这个问题:
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();
这只是一个简化的例子。真正的问题要复杂得多
您可以使用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);
}
};
添加一个间接级别:
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();
}
让超负荷的解决方案发挥作用。
我不知道这是否有意义,但对于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;
}
See Here
相关文章:
- 如何反转整数参数包
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 如何使用默认参数等选择模板专业化
- 模板参数替换失败,并且未完成隐式转换
- 具有默认模板参数的多态类的模板推导失败
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 函数调用中参数的顺序重要吗
- 部分定义/别名模板模板参数
- 模板-模板参数推导:三个不同的编译器三种不同的行为
- 使用不带参数的函数访问结构元素
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 如何在OMNET++中指定与命令行参数组合的输出文件名
- 如何使用Luacneneneba API正确读取字符串和表参数
- 在派生函数中指定void*参数
- 视图中的参数推导失败:take_while
- static_assert在宏中,但也可以扩展到可以用作函数参数的东西
- 使用指向成员的指针将成员函数作为参数传递
- 将参数打包的参数传递到 std::queue 中,以便稍后使用不同的函数调用
- 无效地使用没有参数列表的template-name Queue