c++ - 返回类型的自动扣除
问题描述
在阅读了 C++ auto deduction of return type和C++ : Vector of template class之后,我仍然想知道如何对对象进行泛型操作(例如运算符<<
重载)。我的代码看起来像
#include <map>
#include <memory>
#include <string>
#include <iostream>
/**
* Abstract placeholder for Cache polymorphism
*/
class ICache
{
public:
virtual void update() {};
friend std::ostream & operator << (std::ostream & out, const ICache & IC)
{
out << "you should never print this";
}
};
/**
* Concrete. Coupling a name with some cached value
*/
template<typename T>
class Cache :
public ICache
{
const std::string m_name;
T m_cached;
public:
Cache(const std::string & name) :
m_name(name),
m_cached(0)
{}
void update() override
{
// m_cached is synced with remote resource; action depends both from T and m_name
}
void set(const T t)
{
std::cout << m_name << " setting " << +m_cached << " -> " << +t << std::endl;
m_cached = t;
}
inline T get() const noexcept { return m_cached; }
friend std::ostream & operator << (std::ostream & out, const Cache & O)
{
out << "Cache<" << O.m_name << ", " << O.m_cached << ">";
}
};
class CacheMap
{
std::map<std::string, std::unique_ptr<ICache>> m_map;
template<typename T>
Cache<T>* _get_ptr(const std::string & name) const
{
return reinterpret_cast<Cache<T>*>(m_map.at(name).get());
}
public:
template<typename T>
T get(const std::string & name) const
{
return _get_ptr<T>(name)->get();
}
template <typename T>
void set(const std::string & name, T t)
{
_get_ptr<T>(name)->set(t);
}
template <typename T>
void insert(const std::string & name, T def = 0)
{
std::unique_ptr<ICache> up = std::make_unique<Cache<T>>(name);
m_map.insert({name, std::move(up)});
set<T>(name, def);
}
friend std::ostream & operator << (std::ostream & out, const CacheMap & OM)
{
out << "OM{";
for (const auto & IO : OM.m_map)
out << IO.first << ": " << *(IO.second.get()) << ", "; // ver1
// out << IO.first << ": " << (IO.second->get()) << ", "; // ver2
out << "}";
return out;
}
};
int main()
{
CacheMap m;
int i= 70000;
m.insert<int>("i", 69999);
m.insert<short>("s", 699);
m.insert<char>("c", 69);
m.set("i", i);
std::cout << m << std::endl;
}
标有尾随//ver1
显示you should never print this
的行是有意义的;我正在处理std::unique_ptr<ICache>
对象。
标有尾随的行//ver2
根本不会编译,这也是有道理的。
我想做的是在CacheMap
运行时自动检测(嗯听起来很糟糕)正确的T
,给定一个映射键,以便触发正确reinterpret_cast<>
并检索m_cached
值。
编辑 1
如果使用 编译g++ -O3
,则ver1
行会导致分段违规。
解决方案
只需使用虚拟功能。将变量从Cache<int>
指针类型转换为ICache
指针的时间会丢失有关它的编译时间信息。该信息丢失。您可以dynamic_cast
在您的中使用friend ICache::operator<<
来处理所有不同的类型...要正确解析类型信息,请使用virtual
函数 - 即。与每个类相关的唯一数据。
#include <map>
#include <memory>
#include <string>
#include <iostream>
class ICache
{
public:
virtual ~ICache() {};
virtual void update() {};
// -------- HERE --------------
virtual std::ostream& printme(std::ostream & out) const = 0;
friend std::ostream& operator << (std::ostream & out, const ICache & IC) {
return IC.printme(out);
}
};
template<typename T>
class Cache : public ICache {
const std::string m_name;
T m_cached;
public:
Cache(const std::string & name): m_name(name), m_cached(0) {}
void update() override {}
void set(const T t) {
std::cout << m_name << " setting " << +m_cached << " -> " << +t << std::endl;
m_cached = t;
}
inline T get() const noexcept { return m_cached; }
std::ostream& printme(std::ostream & out) const override {
out << "Cache<" << m_name << ", " << m_cached << ">";
return out;
}
};
class CacheMap {
std::map<std::string, std::unique_ptr<ICache>> m_map;
template<typename T>
Cache<T>* _get_ptr(const std::string & name) const {
return dynamic_cast<Cache<T>*>(m_map.at(name).get());
}
public:
template<typename T>
T get(const std::string & name) const {
return _get_ptr<T>(name)->get();
}
template <typename T>
void set(const std::string & name, T t) {
_get_ptr<T>(name)->set(t);
}
template <typename T>
void insert(const std::string & name, T def = 0) {
std::unique_ptr<ICache> up = std::make_unique<Cache<T>>(name);
m_map.insert({name, std::move(up)});
set<T>(name, def);
}
friend std::ostream& operator << (std::ostream & out, const CacheMap & OM) {
out << "OM{";
for (const auto & IO : OM.m_map)
out << IO.first << ": " << *(IO.second.get()) << ", "; // ver1
// out << IO.first << ": " << (IO.second->get()) << ", "; // ver2
out << "}";
return out;
}
};
int main()
{
CacheMap m;
int i= 70000;
m.insert<int>("i", 69999);
m.insert<short>("s", 699);
m.insert<char>("c", 69);
m.set("i", i);
std::cout << m << std::endl;
}
i setting 0 -> 69999
s setting 0 -> 699
c setting 0 -> 69
i setting 69999 -> 70000
OM{c: Cache<c, E>, i: Cache<i, 70000>, s: Cache<s, 699>, }
我刚刚发现,为了防止非常糟糕且难以调试的错误,我提醒您使用dynamic_cast
而不是reintepret_cast
in CacheMap::_get_ptr()
。
推荐阅读
- database - JDL:多菜单
- markdown - pandoc:未知读者:gfm
- javascript - 服务器和客户端如何通信?
- c# - Unity 无法使用 Admob 解决
- javascript - 在反应状态的嵌套变量上将一个元素插入到另一个列表中
- c# - 当会话在 Asp.net 中过期时如何重定向到主登录页面?
- jmeter - jmeter httpclient4 导致临时 TCP 端口耗尽,而 httpclient3 在 windows 机器中没有导致
- jquery - 每次调用表单提交函数时都会重复
- angular - 使用 contolvalueaccessor 嵌套表单
- javascript - 为什么 video.requestPictureInPicture() 只能工作一次?