ltj*_*jax 25 c++ boost-mpl enable-if
类型在语义上等效时,隐式转换非常有用.例如,假设两个库以相同的方式实现类型,但在不同的命名空间中.或者只是一种大多数相同的类型,除了一些语义糖在这里和那里.现在,您无法将一种类型传递给设计为使用另一种的函数(在其中一个库中),除非该函数是模板.如果不是,你必须以某种方式将一种类型转换为另一种类型.这应该是微不足道的(或者其他类型在后面都不是那么相同!)但是调用转换显然会使代码膨胀,而且函数调用几乎毫无意义.虽然这样的转换函数实际上可能会复制一些值,但它们从高级"程序员"的角度来看基本上什么都不做.
隐式转换构造函数和运算符显然可以提供帮助,但它们引入了耦合,因此其中一种类型必须知道另一种类型.通常,至少在处理库时,情况并非如此,因为其中一种类型的存在使另一种类型变得冗余.此外,您不能总是更改库.
现在我看到有关如何在用户代码中进行隐式转换的两个选项:
第一个是提供代理类型,它为所有涉及的类型实现转换操作符和转换构造函数(和赋值),并始终使用它.
第二个需要对库进行最小的更改,但允许很大的灵活性:为每个可以在外部选择启用的相关类型添加转换构造函数.
例如,对于类型A添加构造函数:
template <class T> A(
const T& src,
typename boost::enable_if<conversion_enabled<T,A>>::type* ignore=0
)
{
*this = convert(src);
}
Run Code Online (Sandbox Code Playgroud)
和一个模板
template <class X, class Y>
struct conversion_enabled : public boost::mpl::false_ {};
Run Code Online (Sandbox Code Playgroud)
默认情况下禁用隐式转换.
然后要启用两种类型之间的转换,请专门化模板:
template <> struct conversion_enabled<OtherA, A> : public boost::mpl::true_ {};
Run Code Online (Sandbox Code Playgroud)
并实现一个convert可以通过ADL找到的函数.
我个人更喜欢使用第二种变体,除非有强烈的反对意见.
现在回答实际问题:关联隐式转换类型的首选方法是什么?我的建议是好主意吗?两种方法都有任何缺点吗?允许这样的转换是危险的吗?如果库类实现者通常会提供第二种方法,那么它们的类型很可能会被软件复制,而这些软件很可能与它们一起使用(我在考虑使用3d渲染中间件,其中大多数软件包实现了3D向量).
如果我对它感到烦恼的话,我宁愿你的"代理"方法胜过其他选择.
问题的真相是,我发现这是所有发展领域中的一个主要问题,我倾向于避免在与特定库交互之外使用任何特定于库的构造.一个例子可能是处理各种不同库中的事件/信号.我已经选择了boost作为我自己的项目代码不可或缺的东西,因此我非常有目的地使用boost :: signals2进行我自己的项目代码中的所有通信.然后我将接口写入我正在使用的UI库.
另一个例子是字符串.每个该死的UI库都重新发明了字符串.我的所有模型和数据代码都使用标准版本,并且我为我的UI包装器提供了接口,这些接口在这些类型中工作...仅在我与UI组件直接交互的那一点上转换为UI特定版本.
这确实意味着我无法利用各种独立但相似的结构提供的大量功能,而且我正在编写大量额外代码来处理这些转换,但这非常值得,因为如果我找到更好的库和/或者需要切换平台它变得更容易这样做,因为我不允许这些东西在整个过程中清除它们的方式.
所以基本上,我更喜欢代理方法,因为我已经在做了.我在抽象层中工作,使我远离我正在使用的任何特定库,并将这些抽象子类化为与所述库交互所需的细节.我总是这样做,所以想知道我想在两个第三方图书馆之间共享信息的一些小区域基本上已经回答了.