我正在尝试实现一个模板化的请求-响应日志类。
这是一个用法示例:
struct RequestA {
std::string data;
};
struct ResponseA {
int code;
};
struct RequestB {
int data;
};
struct ResponseB {
double value;
};
int main(int argc, char* argv[])
{
constexpr std::size_t maxEntries = 5;
RequestJournal<maxEntries, std::pair<RequestA, ResponseA>, std::pair<RequestB, ResponseB>> requestJournal{ 1000 };
auto requestA = std::make_shared<RequestA>(RequestA{ "RequestA data"});
requestJournal.addRequest(0, requestA);
auto requestB = std::make_shared<RequestB>(RequestB{ 10 });
requestJournal.addRequest(1, requestB);
}
其思想是拥有一个不知道请求/响应类型的基础结构类,在创建时注册所有可能的请求-响应对,并能够为请求定义特定的槽。
以下是一个原型(基于此方法link):
inline constexpr std::size_t npos = -1;
template <typename T, typename... Ts>
struct index : std::integral_constant<std::size_t, npos> {};
template <typename T, typename... Ts>
inline constexpr std::size_t index_v = index<T, Ts...>::value;
template <typename T, typename... Ts>
struct index<T, T, Ts...> : std::integral_constant<std::size_t, 0> {};
template <typename T, typename Head, typename... Tail>
class index<T, Head, Tail...>
{
static constexpr std::size_t tmp = index_v<T, Tail...>;
public:
static constexpr std::size_t value = tmp == npos ? tmp : tmp + 1;
};
// Helper function that gets the variant type information for a specific type
template <typename T, typename... Ts>
std::pair<const std::type_info*, std::any> GetVariantTypeInfo(std::variant<Ts...>& variant)
{
// Get the index of the specified type in the variant
constexpr static auto indexOfType = index_v<T, Ts...>;
// Check if the specified type is currently stored in the variant
if (indexOfType == variant.index())
{
auto obj = std::get<indexOfType>(variant);
// Get the type information and object for the specified type
return std::make_pair(&typeid(obj), std::any(obj));
}
// Return a null pointer to indicate that the type information was not found
return std::make_pair(nullptr, std::any());
}
// Helper function that calls GetVariantTypeInfo for each type in a parameter pack
template <typename... Ts>
const std::type_info* GetVariantTypeInfo(std::variant<Ts...>& variant)
{
// Call GetVariantTypeInfo for each type in the parameter pack using fold expression
const std::initializer_list<std::pair<const std::type_info*, std::any>> typeInfos = { GetVariantTypeInfo<Ts, Ts...>(variant)... };
for (const auto& typeInfo : typeInfos)
{
if (typeInfo.first != nullptr)
{
const auto& typeIdx = *typeInfo.first;
return typeInfo.first;
}
}
return nullptr;
}
template <std::size_t maxEntries, typename... Pairs>
class RequestJournal {
public:
using EntryIndex = std::size_t;
using RequestTypesVariant = std::variant<std::shared_ptr<typename Pairs::first_type> ...>;
using ResponseTypesVariant = std::variant<std::shared_ptr<typename Pairs::second_type> ...>;
template <typename T>
static constexpr bool request_is_in_pack = (std::is_same_v<T, typename Pairs::first_type> || ...);
template <typename T>
static constexpr bool response_is_in_pack = (std::is_same_v<T, typename Pairs::second_type> || ...);
RequestJournal(int latencyMsec) {
m_latency = std::chrono::milliseconds(latencyMsec);
}
template <typename T>
std::enable_if_t<response_is_in_pack<T>, void> setResponse(EntryIndex index, std::shared_ptr<T> response) {
const auto requestTypeInfo =
GetVariantTypeInfo<std::shared_ptr<typename Pairs::first_type>...>
(m_journal[index].requestContainer);
// other code ...
}
private:
using Timestamp = std::chrono::time_point<std::chrono::steady_clock>;
struct RequestEntry {
RequestTypesVariant requestContainer;
ResponseTypesVariant responseContainer;
};
RequestJournal() {}
std::size_t i = 0;
std::unordered_map<std::size_t, std::pair<std::type_index, std::type_index>> m_pairsMap{
{ i++, std::make_pair(std::type_index(typeid(typename Pairs::first_type)), std::type_index(typeid(typename Pairs::second_type)))}...
};
std::chrono::milliseconds m_latency;
std::array<RequestEntry, maxEntries> m_journal;
};
问题是如何(以及是否可能)将变量本身(auto obj = std::get<indexOfType>(variant);
)中的对象传播到setResponse
函数。
2条答案
按热度按时间8fq7wneg1#
您需要简化代码并使用
std::visit
。下面是一个使用std::variant
调度响应的简单版本:https://godbolt.org/z/jTYj8o13e输出:
nnt7mjpx2#
好吧,我没有找到在getResponse或其他函数中访问对象本身的方法(std::get〈〉(variant)),但我意识到,实际上我不需要访问它。
我通过将对象进一步传播为std::(更新GetVariantTypeInfo)使其工作,在那里我可以将其转换为模板返回类型,这就是我在返回响应时实际需要的。
我很好奇如何用std::visit实现它,所以很高兴看到这个例子。谢谢大家的帮助。
使用的简化示例: