创建具有多种数据类型的队列
create a queue with multiple data types
我希望能够有一个队列 class 可以接受“任何”首选数据类型,无论是 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
这适用于单一类型(字符串)。但是我怎样才能使它适应上面提到的任何想要的类型呢?
如果你想要一个对象对应一个类型。您必须使用模板 类:
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();
};
但是最好有一个结构来存储基础类型,以便更好地与您的 class API 进行通信。
如果你预先知道要在队列中存储的类型,可以使用std::variant。作为一个类型安全的联合,std::variant
保证它包含一个类型列表;它也比 std::any
具有更好的性能,因为自动存储中存在变体。
例如,此变体类型可以存储 std::string
、int
或 double
之一:
using MyVariant = std::variant<std::string, int, double>;
您可以在 class SafeQueue
中使用 MyVariant
的向量。最后,使用访问者来处理队列中的每个项目。
我在此处对您进行了修改 class:
#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.size() == 0) {
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
我希望能够有一个队列 class 可以接受“任何”首选数据类型,无论是 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 这适用于单一类型(字符串)。但是我怎样才能使它适应上面提到的任何想要的类型呢?
如果你想要一个对象对应一个类型。您必须使用模板 类:
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();
};
但是最好有一个结构来存储基础类型,以便更好地与您的 class API 进行通信。
如果你预先知道要在队列中存储的类型,可以使用std::variant。作为一个类型安全的联合,std::variant
保证它包含一个类型列表;它也比 std::any
具有更好的性能,因为自动存储中存在变体。
例如,此变体类型可以存储 std::string
、int
或 double
之一:
using MyVariant = std::variant<std::string, int, double>;
您可以在 class SafeQueue
中使用 MyVariant
的向量。最后,使用访问者来处理队列中的每个项目。
我在此处对您进行了修改 class:
#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.size() == 0) {
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