- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我有一个名为 caRender 的类,它为 clientObjectTypes 中的每个给定对象类型提供一个 caRender::renderClientObject() 方法。所以下面的代码片段显示了这种运行情况:
#define UNUSED(x) (void)(x)
typedef boost::mpl::vector<Model::ClientModel::cClientVerticesObject,
Model::ClientModel::cRawClientObject> clientObjectTypes;
template <class T>
struct methodForward{
virtual void renderClientObject(T* clientObject,
Controller::QtOpenGL::cQOpenGLContext* glContext) {
UNUSED(clientObject);
UNUSED(glContext);
};
};
struct base {
template<class baseClass, class T>
struct apply {
struct deriveRender: baseClass, methodForward<T> {
virtual ~deriveRender(){};
using baseClass::renderClientObject;
using methodForward<T>::renderClientObject;
};
typedef deriveRender type;
};
template<class T>
struct apply<void, T> {
struct startRender : methodForward<T> {
virtual ~startRender(){};
};
typedef startRender type;
};
};
typedef boost::mpl::fold<clientObjectTypes, void, base>::type caRender;
问:我还想在 renderClientObject 方法中对我的第二个参数(上下文)进行参数抽象。所以目标是获得 n*m 个生成的 renderClientObject 方法,其中 n 定义为数字clientObjectTypes 的数量,m 是上下文类型的数量。我会添加第二个 vector :
typedef boost::mpl::vector<Controller::QtOpenGL::cQOpenGLContext> contextTypes;
但是我不得不考虑如何继续,因为我对元编程这个话题还很陌生。
最佳答案
Update I've since provided an updated version that does match your question more closely (by dispatching on client object and and context). See Live On Coliru.
Update 2 Posted a version adding type-erasure to the mix to get a virtual interface while retaining the other benefits. See Live On Coliru Posting it at the bottom to ensure future retention on SO.
我正在将我的评论转化为答案,因为它提供了更多的空间来阐述。
我的印象是您“只是”试图获得类似语义的多方法(即具有依赖于不止一种对象类型的多态行为的函数)。
在本次演示中,我将使用一些 stub 类型。让我们假设 3 种客户端对象类型[1]:
namespace Model { namespace ClientModel {
struct cClientVerticesObject : boost::noncopyable {};
struct cRawClientObject : boost::noncopyable {};
struct cFunkyClientObject : boost::noncopyable {};
} }
Model::ClientModel::cClientVerticesObject vertices;
Model::ClientModel::cRawClientObject raw;
Model::ClientModel::cFunkyClientObject funky;
让我们看看这些元素的故事是如何展开的:)
在那种情况下,我怀疑普通的多态仿函数可能更切题:
struct RenderClientObjects
{
typedef void result_type;
RenderClientObjects(Controller::QtOpenGL::cQOpenGLContext* glContext)
: glContext(glContext)
{ }
template <typename ClientObject1, typename ClientObject2>
void operator()(ClientObject1 const& clientObject1, ClientObject2 const& clientObject2) const
{
// some implementation
}
private:
Controller::QtOpenGL::cQOpenGLContext* glContext;
};
您可以像使用任何可调用对象一样使用它,依赖于静态分派(dispatch):
RenderClientObjects multimethod(&glContext);
multimethod(vertices, vertices);
multimethod(vertices, funky);
multimethod(raw, vertices);
multimethod(funky, vertices);
boost::variant
!跳过如何提供 //一些实现
的问题,让我跳到它的优雅之处:你可以神奇地使用运行时二进制调度boost::变体
:
/////////////////////////////////////////////////////////////////////
// Variant dispatch (boost apply_visitor supports binary dispatch)
typedef boost::variant<
Model::ClientModel::cClientVerticesObject&,
Model::ClientModel::cRawClientObject&,
Model::ClientModel::cFunkyClientObject&
> ClientObjectVariant;
void variant_multimethod(Controller::QtOpenGL::cQOpenGLContext& ctx, ClientObjectVariant const& a, ClientObjectVariant const& b)
{
boost::apply_visitor(RenderClientObjects(&ctx), a, b);
}
当然,您仍然希望为这些重载提供实现。你可以
这里是一个完整的示例,使用了所有提及的方法并且展示了详尽的静态和运行时分派(dispatch)。
#include <boost/variant.hpp>
#include <boost/utility.hpp>
#include <iostream>
////// STUBS
namespace Model { namespace ClientModel {
struct cClientVerticesObject : boost::noncopyable {};
struct cRawClientObject : boost::noncopyable {};
struct cFunkyClientObject : boost::noncopyable {};
} }
namespace Controller { namespace QtOpenGL {
typedef std::ostream cQOpenGLContext;
} }
////// END STUBS
/////////////////////////////////////////////////////////////////////
// Why not **just** make it a polymorphic functor?
//
// You can make it use an extension point if you're so inclined:
// (note the use of Enable to make it SFINAE-friendly)
namespace UserTypeHooks
{
template <typename ClientObject1, typename ClientObject2, typename Enable = void>
struct RenderClientObjectsImpl
{
void static call(
Controller::QtOpenGL::cQOpenGLContext* glContext,
ClientObject1 const& clientObject1,
ClientObject2 const& clientObject2)
{
(*glContext) << __PRETTY_FUNCTION__ << "\n";
}
};
}
struct RenderClientObjects
{
typedef void result_type;
RenderClientObjects(Controller::QtOpenGL::cQOpenGLContext* glContext)
: glContext(glContext)
{ }
//
void operator()(Model::ClientModel::cFunkyClientObject const& clientObject1, Model::ClientModel::cFunkyClientObject const& clientObject2) const
{
(*glContext) << "Both objects are Funky.\n";
}
template <typename ClientObject2>
void operator()(Model::ClientModel::cFunkyClientObject const& clientObject1, ClientObject2 const& clientObject2) const
{
(*glContext) << "Funky object involved (other is " << typeid(clientObject2).name() << ")\n";
}
template <typename ClientObject1>
void operator()(ClientObject1 const& clientObject1, Model::ClientModel::cFunkyClientObject const& clientObject2) const
{
(*this)(clientObject2, clientObject1); // delegate implementation, for example
}
// catch all:
template <typename ClientObject1, typename ClientObject2>
void operator()(ClientObject1 const& clientObject1, ClientObject2 const& clientObject2) const
{
return UserTypeHooks::RenderClientObjectsImpl<ClientObject1, ClientObject2>::call(glContext, clientObject1, clientObject2);
}
private:
Controller::QtOpenGL::cQOpenGLContext* glContext;
};
/////////////////////////////////////////////////////////////////////
// Demonstrating the user-defined extension point mechanics:
namespace UserTypeHooks
{
template <typename ClientObject>
struct RenderClientObjectsImpl<ClientObject, ClientObject>
{
void static call(
Controller::QtOpenGL::cQOpenGLContext* glContext,
ClientObject const& clientObject1,
ClientObject const& clientObject2)
{
(*glContext) << "Both objects are of the same type (and not funky) : " << typeid(ClientObject).name() << "\n";
}
};
}
/////////////////////////////////////////////////////////////////////
// Variant dispatch (boost apply_visitor supports binary dispatch)
typedef boost::variant<
Model::ClientModel::cClientVerticesObject&,
Model::ClientModel::cRawClientObject&,
Model::ClientModel::cFunkyClientObject&
> ClientObjectVariant;
void variant_multimethod(Controller::QtOpenGL::cQOpenGLContext& ctx, ClientObjectVariant const& a, ClientObjectVariant const& b)
{
RenderClientObjects multimethod(&ctx);
boost::apply_visitor(multimethod, a, b);
}
int main()
{
Controller::QtOpenGL::cQOpenGLContext glContext(std::cout.rdbuf());
RenderClientObjects multimethod(&glContext);
Model::ClientModel::cClientVerticesObject vertices;
Model::ClientModel::cRawClientObject raw;
Model::ClientModel::cFunkyClientObject funky;
glContext << "// Fully static dispatch:\n";
glContext << "//\n";
multimethod(vertices, vertices);
multimethod(vertices, raw);
multimethod(vertices, funky);
//
multimethod(raw, vertices);
multimethod(raw, raw);
multimethod(raw, funky);
//
multimethod(funky, vertices);
multimethod(funky, raw);
multimethod(funky, funky);
glContext << "\n";
glContext << "// Runtime dispatch:\n";
glContext << "//\n";
variant_multimethod(glContext, vertices, vertices);
variant_multimethod(glContext, vertices, raw);
variant_multimethod(glContext, vertices, funky);
//
variant_multimethod(glContext, raw, vertices);
variant_multimethod(glContext, raw, raw);
variant_multimethod(glContext, raw, funky);
//
variant_multimethod(glContext, funky, vertices);
variant_multimethod(glContext, funky, raw);
variant_multimethod(glContext, funky, funky);
}
哦,为了完整起见,这里是输出:
g++-4.8 -Os -Wall -pedantic main.cpp && ./a.out | c++filt -t
// Fully static dispatch:
//
Both objects are of the same type (and not funky) : Model::ClientModel::cClientVerticesObject
static void UserTypeHooks::RenderClientObjectsImpl<ClientObject1, ClientObject2, Enable>::call(Controller::QtOpenGL::cQOpenGLContext*, const ClientObject1&, const ClientObject2&) [with ClientObject1 = Model::ClientModel::cClientVerticesObject; ClientObject2 = Model::ClientModel::cRawClientObject; Enable = void; Controller::QtOpenGL::cQOpenGLContext = std::basic_ostream<char>]
Funky object involved (other is Model::ClientModel::cClientVerticesObject)
static void UserTypeHooks::RenderClientObjectsImpl<ClientObject1, ClientObject2, Enable>::call(Controller::QtOpenGL::cQOpenGLContext*, const ClientObject1&, const ClientObject2&) [with ClientObject1 = Model::ClientModel::cRawClientObject; ClientObject2 = Model::ClientModel::cClientVerticesObject; Enable = void; Controller::QtOpenGL::cQOpenGLContext = std::basic_ostream<char>]
Both objects are of the same type (and not funky) : Model::ClientModel::cRawClientObject
Funky object involved (other is Model::ClientModel::cRawClientObject)
Funky object involved (other is Model::ClientModel::cClientVerticesObject)
Funky object involved (other is Model::ClientModel::cRawClientObject)
Both objects are Funky.
// Runtime dispatch:
//
Both objects are of the same type (and not funky) : Model::ClientModel::cClientVerticesObject
static void UserTypeHooks::RenderClientObjectsImpl<ClientObject1, ClientObject2, Enable>::call(Controller::QtOpenGL::cQOpenGLContext*, const ClientObject1&, const ClientObject2&) [with ClientObject1 = Model::ClientModel::cClientVerticesObject; ClientObject2 = Model::ClientModel::cRawClientObject; Enable = void; Controller::QtOpenGL::cQOpenGLContext = std::basic_ostream<char>]
Funky object involved (other is Model::ClientModel::cClientVerticesObject)
static void UserTypeHooks::RenderClientObjectsImpl<ClientObject1, ClientObject2, Enable>::call(Controller::QtOpenGL::cQOpenGLContext*, const ClientObject1&, const ClientObject2&) [with ClientObject1 = Model::ClientModel::cRawClientObject; ClientObject2 = Model::ClientModel::cClientVerticesObject; Enable = void; Controller::QtOpenGL::cQOpenGLContext = std::basic_ostream<char>]
Both objects are of the same type (and not funky) : Model::ClientModel::cRawClientObject
Funky object involved (other is Model::ClientModel::cRawClientObject)
Funky object involved (other is Model::ClientModel::cClientVerticesObject)
Funky object involved (other is Model::ClientModel::cRawClientObject)
Both objects are Funky.
“更新 2”的完整代码:
#include <typeinfo>
#include <boost/type_traits.hpp>
#include <iostream>
////// STUBS
struct move_only { // apparently boost::noncopyable prohibits move too
move_only(move_only const&) = delete;
move_only(move_only&&) = default;
move_only() = default;
};
namespace Model { namespace ClientModel {
struct cClientVerticesObject : move_only {};
struct cRawClientObject : move_only {};
struct cFunkyClientObject : move_only {};
} }
namespace Controller {
namespace QtOpenGL {
struct cQOpenGLContext : move_only {};
}
struct cConsoleContext : move_only {};
struct cDevNullContext : move_only {};
}
namespace traits
{
template <typename T> struct supports_console_ctx : boost::mpl::false_ {};
template <>
struct supports_console_ctx<Model::ClientModel::cFunkyClientObject> : boost::mpl::true_ {};
}
////// END STUBS
/////////////////////////////////////////////////////////////////////
// Why not **just** make it a polymorphic functor?
//
// You can make it use an extension point if you're so inclined:
// (note the use of Enable to make it Sfinae-friendly)
namespace UserTypeHooks
{
template <typename ClientObject, typename Context, typename Enable = void>
struct RenderClientObjectsImpl
{
void static call(ClientObject const& clientObject, Context const& context)
{
// static_assert(false, "not implemented");
// throw?
std::cout << "NOT IMPLEMENTED:\t" << __PRETTY_FUNCTION__ << "\n";
}
};
template <typename ClientObject>
struct RenderClientObjectsImpl<ClientObject, Controller::QtOpenGL::cQOpenGLContext>
{
void static call(ClientObject const& clientObject, Controller::QtOpenGL::cQOpenGLContext const& context)
{
std::cout << "cQOpenGLContext:\t" << typeid(ClientObject).name() << "\n";
}
};
template <typename ClientObject>
struct RenderClientObjectsImpl<ClientObject, Controller::cDevNullContext>
{
void static call(ClientObject const& clientObject, Controller::cDevNullContext const& context)
{
std::cout << "devnull:\t\t" << typeid(ClientObject).name() << "\n";
}
};
}
struct RenderClientObjects
{
typedef void result_type;
template <typename ClientObject, typename Context>
void operator()(ClientObject const& clientObject, Context const& context) const
{
return UserTypeHooks::RenderClientObjectsImpl<ClientObject, Context>::call(clientObject, context);
}
};
/////////////////////////////////////////////////////////////////////
// Demonstrating the user-defined extension point mechanics:
namespace UserTypeHooks
{
template <typename ClientObject>
struct RenderClientObjectsImpl<ClientObject, Controller::cConsoleContext,
typename boost::enable_if<traits::supports_console_ctx<ClientObject> >::type>
{
void static call(
ClientObject const& clientObject,
Controller::cConsoleContext const& context)
{
std::cout << "This type has cConsoleContext support due to the supports_console_ctx trait! " << typeid(ClientObject).name() << "\n";
}
};
}
/////////////////////////////////////////////////////////////////////
// Added: Dynamic interface
//
// Making this a bit more complex than you probably need, but hey, assuming the
// worst:
#include <memory>
struct IPolymorphicRenderable
{
// you likely require only one of these, and it might not need to be
// virtual
virtual void render(Controller::QtOpenGL::cQOpenGLContext& ctx) = 0;
virtual void render(Controller::cConsoleContext& ctx) = 0;
virtual void render(Controller::cDevNullContext& ctx) = 0;
};
struct IClientObject : IPolymorphicRenderable
{
template <typename T> IClientObject(T&& val) : _erased(new erasure<T>(std::forward<T>(val))) { }
virtual void render(Controller::QtOpenGL::cQOpenGLContext& ctx) { return _erased->render(ctx); }
virtual void render(Controller::cConsoleContext& ctx) { return _erased->render(ctx); }
virtual void render(Controller::cDevNullContext& ctx) { return _erased->render(ctx); }
private:
template <typename T> struct erasure : IPolymorphicRenderable
{
erasure(T val) : _val(std::move(val)) { }
void render(Controller::QtOpenGL::cQOpenGLContext& ctx) { return RenderClientObjects()(_val, ctx); }
void render(Controller::cConsoleContext& ctx) { return RenderClientObjects()(_val, ctx); }
void render(Controller::cDevNullContext& ctx) { return RenderClientObjects()(_val, ctx); }
T _val;
};
std::unique_ptr<IPolymorphicRenderable> _erased;
};
int main()
{
Controller::QtOpenGL::cQOpenGLContext glContext;
Controller::cConsoleContext console;
Controller::cDevNullContext devnull;
std::cout << "// Fully virtual dispatch\n";
std::cout << "//\n";
IClientObject obj = Model::ClientModel::cClientVerticesObject();
obj.render(glContext);
obj.render(console);
obj.render(devnull);
//
obj = Model::ClientModel::cRawClientObject();
obj.render(glContext);
obj.render(console);
obj.render(devnull);
//
obj = Model::ClientModel::cFunkyClientObject();
obj.render(glContext);
obj.render(console);
obj.render(devnull);
}
输出:
clang++ -std=c++11 -Os -Wall -pedantic main.cpp && ./a.out
// Fully virtual dispatch
//
cQOpenGLContext: N5Model11ClientModel21cClientVerticesObjectE
NOT IMPLEMENTED: static void UserTypeHooks::RenderClientObjectsImpl<Model::ClientModel::cClientVerticesObject, Controller::cConsoleContext, void>::call(const ClientObject &, const Context &) [ClientObject = Model::ClientModel::cClientVerticesObject, Context = Controller::cConsoleContext, Enable = void]
devnull: N5Model11ClientModel21cClientVerticesObjectE
cQOpenGLContext: N5Model11ClientModel16cRawClientObjectE
NOT IMPLEMENTED: static void UserTypeHooks::RenderClientObjectsImpl<Model::ClientModel::cRawClientObject, Controller::cConsoleContext, void>::call(const ClientObject &, const Context &) [ClientObject = Model::ClientModel::cRawClientObject, Context = Controller::cConsoleContext, Enable = void]
devnull: N5Model11ClientModel16cRawClientObjectE
cQOpenGLContext: N5Model11ClientModel18cFunkyClientObjectE
This type has cConsoleContext support due to the supports_console_ctx trait! N5Model11ClientModel18cFunkyClientObjectE
devnull: N5Model11ClientModel18cFunkyClientObjectE
[1](我已经确保客户端对象不被假定为对于此示例是可复制的,但实际上,您可能想要在你的更多库中使用 ClientObjectVariant
作为值类型)
关于c++ - boost::mpl::fold 用于双参数抽象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21483102/
下面的代码再现了一个我真的不理解 boost MPL 库的行为: #include #include #include using namespace boost; int main() {
我正在尝试使用 boost.mpl 编写一个小型元程序,该程序使用两个 channel 映射将“命名 channel ”与音频格式相匹配。 名称也是一个整数(枚举)。我试图在运行时实现的一个简单示例可
我正在尝试在 for_each 中使用 mpl_list #include #include #include #include #include #include #include #
我正在尝试对 mpl::string 应用转换,但无法对其进行编译。我正在使用 MS VC++2010 和 Boost 1.43.0。代码: #include #include #include
我正在尝试运行几年前编写的代码,该代码使用 matplotlib 中的 mpl。以前运行得很好,但现在突然抛出错误: from matplotlib import mpl ImportError: c
Boost MPL 文档指出 boost::map::equal "如果两个序列 Seq1 和 Seq2比较 _element_ _element_ 时是相同的。 但似乎没有检查关联序列映射是否相等元
假设我有一个 boost::mpl::vector “myvec”,例如这样定义: using myvec = boost::mpl::vector; 现在我想定义另一种类型 myvecex,它将每个
下面的代码尝试测试 boost::mpl::or_ 和 boost::mpl::and_ 的短路行为: #include #include #include #include #include
假设我有这些类型: template class Storage > struct AbstractFactoryUnit { virtual ~AbstractFactoryUnit()
我有一个类型列表定义为: typedef boost::mpl::list OriginalList; 我想创建不包含任何水果的第二个列表,即从第一个列表形成的结果列表将包含单一类型的 Brick。
我有以下内容: class Message { public: bool process() { return doProcess(); } protected
我试图在编译时使用 boost-mpl 连接字符串,但从 gcc 中收到错误。这是示例 - using namespace boost; using namespace std; template s
天哪,在使用 mpl 库时,弄清楚语法是一个碰运气的经历 (previous question)。比较两个 mpl 迭代器的正确语法是什么 - 即 it != v.end() 测试? template
我目前正致力于在我的应用程序中实现“捐赠”选项,并决定使用 PayPal(请参阅:Donate via in-app billing) 阅读文档等后,决定使用 PayPal 移动支付库 (MPL)。一
我想使用编译时 (MPL) for_each 检查给定的输入变量是否在 MPL 数组中,并再次从 MPL 数组中获取和获取输出变量。我正在尝试使用具有 2 个参数的函数对象,即 MPL 类型和输入。
我知道以下代码不起作用,因为 i 是运行时参数而不是编译时参数。但我想知道,是否有办法实现同样的目标。我有一个类列表,我需要调用其中每个类的模板函数。 void GucTable::refreshSe
我正在浏览 tutorial关于生成式编程,我偶然发现了MPL-value idiom: template class A { A(); public: static const A
我有元函数 FibIter。它计算与斐波那契数列中的数字(参数 Iter)对应的斐波那契数。然后我使用 mpl::transform 创建具有从 0 到 N 的斐波那契数列的 mpl::vector。
我试图用一些容器将每个元素包装在 mpl::set 中,例如 std::vector,尽管实际类型并不重要.我该怎么做?基本上我想从这里开始 using mySet = mpl::set; 对此 us
我有一个像这样的 boost::mpl 序列: typedef boost::mpl::vector TTypes; 我有一个特定用途的容器类,我想从我的 dll 中导出它: template cla
我是一名优秀的程序员,十分优秀!