我希望能够有一个队列类,可以接受"any"首选的数据类型,无论是CURL类型还是std::string类型。字符串队列或旋转句柄队列
#pragma once
#include <iostream>
#include <queue>
#include <string>
#include <mutex>
#include <condition_variable>
#include <chrono>
#include "queue_safe.h"
void SafeQueue::initialize() {
/* initialize a std::queue */
safe_queue = {};
}
std::string SafeQueue::get() {
std::unique_lock<std::mutex> condition_lock(queue_lock);
if (safe_queue.empty()) {
if (ready.wait_for(condition_lock, std::chrono::seconds(20)) == std::cv_status::timeout) {
/* timeout was reached, no items left */
return std::string();
}
/* if a timeout was not hit, but the queue was empty previously this will execute */
std::string element = safe_queue.front();
safe_queue.pop();
return element;
}
else {
/* not empty, return an element */
std::string element = safe_queue.front();
safe_queue.pop();
return element;
}
/* do not need a return value here since empty HAS to be either true/false */
}
void SafeQueue::put(std::string& element) {
std::lock_guard<std::mutex> put_guard(queue_lock);
safe_queue.push(element);
ready.notify_one();
}
uint8_t SafeQueue::empty() {
std::lock_guard<std::mutex> empty_guard(queue_lock);
if (safe_queue.size() == 0) {
return 1;
}
return 0;
}
queue.cpp
#pragma once
#include <string>
#include <mutex>
#include <queue>
#include <condition_variable>
class SafeQueue {
public:
std::condition_variable ready;
std::mutex queue_lock;
std::queue<std::string> safe_queue;
uint8_t empty();
void initialize();
void put(std::string& element);
std::string get();
};
queue.h这对于单一类型(字符串)来说工作得很好。但是我怎样才能使它适应上面提到的任何想要的类型呢?
如果您事先知道要在队列中存储的类型,则可以使用std::variant。作为类型安全的联合,std::variant
保证它包含类型列表中的一个;由于在自动存储中存在一个变体,因此它的性能也优于std::any
。
例如,此变体类型可以存储std::string
,int
或double
中的一种:
using MyVariant = std::variant<std::string, int, double>;
你可以在SafeQueue
类中使用MyVariant
队列。最后,使用访问者来处理队列中的每个项目。
我在这里重写了你的类:
#include <iostream>
#include <iomanip>
#include <mutex>
#include <queue>
#include <condition_variable>
#include <variant>
#include <vector>
using MyVariant = std::variant<std::string, int, double>;
template<class> inline constexpr bool always_false_v = false;
class SafeQueue {
public:
std::condition_variable ready;
std::mutex queue_lock;
std::queue<MyVariant> safe_queue;
uint8_t empty();
void initialize();
void put(MyVariant element);
MyVariant get();
};
void SafeQueue::initialize() {
/* initialize a std::queue */
safe_queue = {};
}
MyVariant SafeQueue::get() {
std::unique_lock<std::mutex> condition_lock(queue_lock);
if (safe_queue.empty()) {
if (ready.wait_for(condition_lock, std::chrono::seconds(20)) == std::cv_status::timeout) {
/* timeout was reached, no items left */
return std::string();
}
/* if a timeout was not hit, but the queue was empty previously this will execute */
auto element = safe_queue.front();
safe_queue.pop();
return element;
}
else {
/* not empty, return an element */
auto element = safe_queue.front();
safe_queue.pop();
return element;
}
/* do not need a return value here since empty HAS to be either true/false */
}
void SafeQueue::put(MyVariant element) {
{
std::lock_guard<std::mutex> put_guard(queue_lock);
safe_queue.push(std::move(element));
}
ready.notify_one();
}
uint8_t SafeQueue::empty() {
std::lock_guard<std::mutex> empty_guard(queue_lock);
if (safe_queue.empty()) {
return 1;
}
return 0;
}
int main()
{
SafeQueue q;
q.put("hello");
q.put(1);
q.put(2.3);
//Use visitor pattern to print elements from queue
while (!q.empty()) {
auto elem = q.get();
std::visit([](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, std::string>)
std::cout << "std::string with value " << std::quoted(arg) << 'n';
else if constexpr (std::is_same_v<T, int>)
std::cout << "int with value " << arg << 'n';
else if constexpr (std::is_same_v<T, double>)
std::cout << "double with value " << arg << 'n';
else
static_assert(always_false_v<T>, "non-exhaustive visitor!");
}, elem);
}
}
输出:
std::string with value "hello"
int with value 1
double with value 2.3
演示如果你想让一个对象对应一个类型。你必须使用模板类:
template <typename T>
class SafeQueue {
public:
std::condition_variable ready;
std::mutex queue_lock;
std::queue<T> safe_queue;
uint8_t empty();
void initialize();
void put(T& element);
T get();
};
但是如果你需要一个具有多层类型的队列,你可以使用std::any
:
class SafeQueue {
public:
std::condition_variable ready;
std::mutex queue_lock;
std::queue<std::any> safe_queue;
uint8_t empty();
void initialize();
void put(std::any& element);
std::any get();
};
但是最好有一个结构来存储底层类型,以便更好地与类API通信。