大家好)我已經撰寫了簡單的反序列化函式,它能夠反序列化任何型別的物件。這是這個函式的原型:
template <typename T>
T deserialize(bit_reader &aReader) noexcept;
我也將此函式放入僅標頭庫中。下面你可以看到這個庫的源代碼(現在它只包含一個檔案bits.h):
//--------------------- file bits.h ---------------------
#ifndef bits_h
#define bits_h
#include <type_traits>
namespace bits
{
// code below allows to check whether some function or method is defined and can be called
// for details see: https://en.cppreference.com/w/cpp/experimental/is_detected
namespace details
{
template <class Default, class AlwaysVoid, template <class...> class Op,
class... Args>
struct detector
{
using value_t = std::false_type;
using type = Default;
};
template <class Default, template <class...> class Op, class... Args>
struct detector<Default, std::void_t<Op<Args...>>, Op, Args...>
{
using value_t = std::true_type;
using type = Op<Args...>;
};
} // namespace details
struct nonesuch
{
~nonesuch() = delete;
nonesuch(nonesuch const&) = delete;
void operator=(nonesuch const&) = delete;
};
template <template <class...> class Op, class... Args>
using is_detected =
typename details::detector<nonesuch, void, Op, Args...>::value_t;
template <template <class...> class Op, class... Args>
constexpr inline bool is_detected_v = is_detected<Op, Args...>::value;
template <template <class...> class Op, class... Args>
using detected_t =
typename details::detector<nonesuch, void, Op, Args...>::type;
template <class Default, template <class...> class Op, class... Args>
using detected_or = details::detector<Default, void, Op, Args...>;
template <class Default, template <class...> class Op, class... Args>
using detected_or_t = typename detected_or<Default, Op, Args...>::type;
template <class Expected, template <class...> class Op, class... Args>
using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
template <class Expected, template <class...> class Op, class... Args>
constexpr inline bool is_detected_exact_v =
is_detected_exact<Expected, Op, Args...>::value;
template <class To, template <class...> class Op, class... Args>
using is_detected_convertible =
std::is_convertible<detected_t<Op, Args...>, To>;
template <class To, template <class...> class Op, class... Args>
constexpr inline bool is_detected_convertible_v =
is_detected_convertible<To, Op, Args...>::value;
template <typename T>
struct tag_t
{
};
template <typename T>
constexpr tag_t<T> tag{};
class bit_reader
{};
template <class T>
using deserializable_t = decltype(deserialize(std::declval<bit_reader &>(), tag<T>));
template <typename T>
inline constexpr bool is_deserializable_v = is_detected_v<deserializable_t, T>;
template <typename T>
T deserialize(bit_reader &aReader) noexcept
{
if constexpr (is_deserializable_v<T>)
{
return deserialize<T>(aReader, tag<T>);
}
else
{
static_assert(is_deserializable_v<T>, "Function 'deserialize' is not found.");
}
return T{};
}
} // namespace bits
#endif /* bits_h */
例如,要反序列化uint16_t,撰寫如下內容就足夠了:
bit_reader reader{};
uint16_t value = deserialize<uint16_t>(reader);
此外,我希望該用戶可以為任何型別提供他自己的反序列化函式實作,而無需對庫進行任何更改。例如,如果我的庫沒有實作反序列化,uint16_t則用戶可以將其添加到自己的檔案中,如下所示:
//--------------------- file user.cpp ---------------------
#include <cstdint>
#include <iostream>
#include "bits.h"
namespace bits
{
template <typename T>
using enable_if_uint16_t =
std::enable_if_t<std::is_same_v<std::decay_t<T>, uint16_t>, T>;
// user difined deserialization for uint16_t
template <typename T>
T deserialize(bit_reader &, tag_t<enable_if_uint16_t<T>>) noexcept
{
uint16_t value{10};
return value;
}
} // namespace bits
using bit_reader = bits::bit_reader;
int main(int, char **)
{
bit_reader reader{};
uint16_t restored = bits::deserialize<uint16_t>(reader);
std::cout << "restored: " << restored << '\n' << std::endl;
return 0;
}
問題是if constexpr (is_deserializable_v<T>)函式中的條件template <typename T> T deserialize(bit_reader &aReader) noexcept永遠不會回傳true。
順便說一句,我設法通過輸入引數而不是回傳值提供反序列化值來使其作業。相應修改功能后:
...
// user difined deserialization for uint16_t
template <typename T>
T deserialize(bit_reader &, tag_t<enable_if_uint16_t<T>>) noexcept
...
變成:
...
// user difined deserialization for uint16_t
template <typename T>
void deserialize(T&, bit_reader &, tag_t<enable_if_uint16_t<T>>) noexcept
...
但是在我看來,當通過回傳值將反序列化的值傳遞給用戶時,第一個原型似乎更自然。是否可以在不改變將反序列化值傳遞到呼叫站點的方式的情況下if constexpr (is_deserializable_v<T>)回傳條件?true考慮到我使用 C 17。
uj5u.com熱心網友回復:
這里的問題是編譯器在推導模板的型別T時遇到了麻煩tag_t<enable_if_uint16_t<T>>,我建議你將 SFINAE 部分放在回傳型別中,因為tag<T>它是可推導的。
// user difined deserialization for uint16_t
template <typename T>
enable_if_uint16_t<T> deserialize(bit_reader &, tag_t<T>) noexcept
演示
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/515146.html
標籤:C 模板C 17
上一篇:Python,為函式創建一種模板
下一篇:C 20概念對模板化函式應用約束
