- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在使用 C++ (vc2008) 读/写一个结构,其类型在运行时显然会根据 ID 标志发生变化。创建正确的类型和/或读取和写入将需要转换。最接近的现有示例是 Using template instead of switch但这不允许在运行时指定类型。为了避免在多个地方创建相同的开关,我一直在研究使用递归模板来解决这个问题。这是我第一次使用这些,因此可能会对代码示例进行一些重大改进!
下面是一个工作示例。正如您将在“main()”中看到的,使用的类型 id 是一个变量 int,可以将其设置为任何运行时值。在 TypeList<> 上调用函数将递归类型,直到它到达匹配的 ID 或空类型。
#include <stdio.h>
#include <iostream>
//Base type
struct Base
{
//NOTE: The virtual destructor can be added to aid with debugging
//virtual ~Base(){}
friend std::ostream& operator << ( std::ostream& stream, const Base& rhs )
{ return stream << "Base"; }
};
struct A : Base
{
friend std::ostream& operator << ( std::ostream& stream, const A& rhs )
{ return stream << "A"; }
};
struct B : Base
{
friend std::ostream& operator << ( std::ostream& stream, const B& rhs )
{ return stream << "B"; }
};
struct C : Base
{
friend std::ostream& operator << ( std::ostream& stream, const C& rhs )
{ return stream << "C"; }
};
//Recursive template type
// - If the ID/key does not match the next type is checked and so on
template < unsigned int kID, typename _Type, typename _TNext >
struct TypeList
{
typedef _Type Type;
typedef typename _TNext::Base Base;
static Base* doNew( unsigned int id )
{ return id == kID ? new _Type() : (Base*)_TNext::doNew(id); }
static void doDelete(unsigned int id, Base* rhs )
{ id == kID ? delete (_Type*)rhs : _TNext::doDelete(id, rhs ); }
static std::ostream& doWrite( unsigned int id, std::ostream& stream, const Base* rhs )
{ return id == kID ? stream << (*(const _Type*)rhs) : _TNext::doWrite(id, stream, rhs); }
};
//Specialise the 'void' case to terminate the list
// TODO; this doesn't seem as elegant as possible!? How can we separate the logic from the functionality better...
template < unsigned int kID, typename _Type >
struct TypeList<kID, _Type, void>
{
typedef _Type Type;
typedef _Type Base;
static _Type* doNew( unsigned int id )
{ return id == kID ? new _Type() :0; }
static void doDelete(unsigned int id, _Type* rhs )
{ if ( id == kID ) delete rhs; }
static std::ostream& doWrite( unsigned int id, std::ostream& stream, const _Type* rhs )
{ return id == kID ? stream << (*(const _Type*)rhs) : stream; }
};
// ID values used to identify the different structure types
enum eID
{
ID_A,
ID_B,
ID_C,
};
//Create our ID and Type list
typedef TypeList< ID_A, A,
TypeList< ID_B, B,
TypeList< ID_C, C,
TypeList< -1 , Base, void> > > > TypesList;
int _tmain(int argc, _TCHAR* argv[])
{
eID type = ID_C; //, We are dealing with a type of 'C'
Base* newInst = TypesList::doNew( type ); //Create a new C
TypesList::doWrite( type, std::cout, newInst ); //Write 'C' to the console
TypesList::doDelete( type, newInst ); //Delete C
return 0;
}
人们对此以及其他/更好的方法有何看法?主要是有一种方法可以很好地将逻辑与类的功能分开,以节省 TypeList<,,_Type> 和 TypeList<,,void> 实例化中的重复代码。
编辑:该解决方案最好不需要运行时设置来将类型“添加”到查找等。
干杯,克雷格
最佳答案
这个解决方案有很多缺点,这使它在我看来不是最佳选择。大部分原因归结为 TypeList 成为主要的编译瓶颈,就像 switch case 一样。以我的经验,本例中的 doWrite/doDelete 通过虚拟调度更好地解决,但实际对象创建需要将运行时数据映射到具体类型。在我看来,最好的解决方案就是去工厂。如果你有 Loki很简单:
// BaseFactory.h
typedef Loki::SingletonHolder< Loki::Factory< Base, std::string > > BaseFactory;
#define REGISTER_BASE_FACTORY( x ) \
static bool BOOST_PP_CAT( registerBaseFac, x ) = BaseFactory::Instance().Register( BOOST_PP_STRINGIZE( x ), boost::phoenix::new_< x >() );
// For example A.cpp
REGISTER_BASE_FACTORY( x );
// Somewhere else
...
Base* someInstance = BaseFactory::Instance().CreateObject("A");
assert( typeid( *someInstance ) == typeid( A ) );
...
我个人使用不同的工厂基地,它更类似于:
#pragma once
#include "boost/unordered_map.hpp"
#include <cassert>
template< typename KeyType, typename ProductCreatorType >
class Factory
{
typedef boost::unordered_map< KeyType, ProductCreatorType > CreatorMap;
public:
const ProductCreatorType& operator()( const KeyType& a_Key ) const
{
typename CreatorMap::const_iterator itrFnd = m_Creators.find( a_Key );
assert( itrFnd != m_Creators.end() );
return itrFnd->second;
}
ProductCreatorType& operator()( const KeyType& a_Key )
{
typename CreatorMap::iterator itrFnd = m_Creators.find( a_Key );
assert( itrFnd != m_Creators.end() );
return itrFnd->second;
}
bool RegisterCreator( const KeyType& a_Key, const ProductCreatorType& a_Creator )
{
return m_Creators.insert( std::make_pair( a_Key, a_Creator ) ).second;
}
private:
CreatorMap m_Creators;
};
仅仅是因为它更灵活(能够处理例如返回 boost::shared_ptr<>
)。
这种方法的主要优点是您可以在与具体类型相同的翻译单元中拥有注册码。更容易分离客户端和库代码并且修改具体类型不会导致重新编译需要工厂的所有内容。作为奖励,性能规模也更好。
如果您不想要虚拟分派(dispatch),您可以使用相同的方法,而是使用成员函数指针并提供实例,这可以使用几乎相同的方法使用 boost::bind
来解决。 .
编辑:是的,错过了您希望它完全基于编译时间的想法,尽管老实说我看不到任何好处。
关于c++ - 递归模板列表而不是基于键/id 搜索的硬编码 switch 语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11982808/
我在我的应用程序中使用 Hibernate Search。其中一个子集合被映射为 IndexedEmbedded。子对象有两个字段,一个是 id,另一个是日期(使用日期分辨率到毫秒)。当我搜索 id=
The App Engine Search API有一个 GeoPoint 字段。可以用它来进行半径搜索吗?例如,给定一个 GeoPoint,查找位于特定半径内的所有文档。 截至目前,它看起来像 Ge
客户对我正在做的员工管理项目提出了这个新要求,以允许他们的用户进行自定义 bool 搜索。 基本上允许他们使用:AND、OR、NOT、括号和引号。 实现它的最佳方法是什么?我检查了 mysql,它们使
很想知道哪个更快 - 如果我有一个包含 25000 个键值对的数组和一个包含相同信息的 MySQL 数据库,搜索哪个会更快? 非常感谢大家! 最佳答案 回答这个问题的最好方法是执行基准测试。 关于ph
我喜欢 smartcase,也喜欢 * 和 # 搜索命令。但我更希望 * 和 # 搜索命令区分大小写,而/和 ?搜索命令遵循 smartcase 启发式。 是否有隐藏在某个地方我还没有找到的设置?我宁
我有以下 Marklogic 查询,当在查询控制台中运行时,它允许我检索具有管理员权限的系统用户: xquery version "1.0-ml"; import schema namespace b
我希望当您搜索例如“A”时,所有以“A”开头的全名都会出现。因此,如果名为“Andreas blabla”的用户将显示 我现在有这个: $query = "SELECT full_name, id,
我想在我的网站上添加对人名的搜索。好友列表已经显示在页面上。 我喜欢 Facebook 这样做的方式,您开始输入姓名,Facebook 只会显示与查询匹配的好友。 http://cl.ly/2t2V0
您好,我在我的网站上进行搜索时遇到此错误。 Fatal error: Uncaught Error: Call to undefined function mysql_connect() in /ho
声明( 叠甲 ):鄙人水平有限,本文为作者的学习总结,仅供参考。 1. 搜索介绍 搜索算法包括深度优先搜索(DFS)和广度优先搜索(BFS)这两种,从起点开始,逐渐扩大
我正在为用户列表使用 FuturBuilder。我通过 futur: fetchpost() 通过 API 获取用户。在专栏的开头,我实现了一个搜索栏。那么我该如何实现我的搜索栏正在搜索呢? Cont
我正在使用 MVC5,我想搜索结果并停留在同一页面,这是我在 Controller (LiaisonsProjetsPPController) 中执行搜索操作的方法: public ActionRes
Azure 搜索中的两种方法 Upload 与 MergeOrUpload 之间有什么区别。 他们都做完全相同的事情。即,如果文档不存在,它们都会上传文档;如果文档已经存在,则替换该文档。 由于这两种
实际上,声音匹配/搜索的当前状态是什么?我目前正在远程参与规划一个 Web 应用程序,该应用程序将包含和公开记录的短音频剪辑(最多 3-5 秒,人名)的数据库。已经提出了一个问题,是否可以实现基于用户
在商业应用程序中,具有数百个面并不罕见。当然,并非所有产品都带有所有这些标记。 但是在搜索时,我需要添加一个方面查询字符串参数,其中列出了我想要返回的所有方面。由于我事先不知道相关列表,因此我必须在查
当我使用nvcc 5.0编译.cu文件时,编译器会为我提供以下信息。 /usr/bin/ld: skipping incompatible /usr/local/cuda-5.0/lib/libcud
我正在使用基于丰富的 Lucene 查询解析器语法的 Azure 搜索。我将“~1”定义为距离符号的附加参数)。但我面临的问题是,即使存在完全匹配,实体也没有排序。 (例如,“blue~1”将返回“b
我目前有 3 个类,一个包含 GUI 的主类,我在其中调用此方法,一个包含数据的客户类,以及一个从客户类收集数据并将其放入数组列表的 customerList 类,以及还包含搜索数组列表方法。 我正在
假设我有多个 6 字符的字母数字字符串。 abc123、abc231、abc456、cba123、bac231 和 bac123 。 基本上我想要一个可以搜索和列出所有 abc 实例的选择语句。 我只
我有这个表 "Table"内容: +--------+ | Serial | +--------+ | d100m | <- expected result | D100M | <- expect
我是一名优秀的程序员,十分优秀!