创建具有多种数据类型的队列



我希望能够有一个队列类,可以接受"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,intdouble中的一种:

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通信。

最新更新