我有一个容器类,可以处理各种格式的像素。某些格式只将像素存储在内存中,因此容器的引用类型为Pixel&。其他格式将像素存储在压缩字节中。没有什么可以返回引用,因此在这种情况下引用类型是代理类型。我的所有代理类型都有一个名为value_type的嵌入式typedef,它是底层像素的类型。
当我尝试编写对像素进行操作的仿函数时,我遇到了问题。例如,我希望能够写出如下内容:
std::for_each( container.begin(), container.end(), Incrementer() );
我已经能够以两种不同的方式使用它,但我不喜欢它们中的任何一种,所以我想知道这是否可以改进。
第一种方法是:
struct Incrementer {
template <typename Pixel>
void operator()( Pixel& p ) {
p = p + 1;
}
template <typename Proxy>
void operator()( Proxy p, typename Proxy::value_type* dummy=0 ) {
p = p + 1;
}
};
基本思想是我有两个重载,一个用于容器返回像素引用的情况,另一个用于返回代理。我需要第二次重载的伪参数,以便参考案例是明确的。这个问题是我使用的每个仿函数都需要这两个重载(包括伪参数),所以我觉得界面相当丑陋。
也许我可以编写一些模板魔法来整理参数类型,但我一直遇到编译器永远不会推断出引用参数的问题,所以我需要提供一个非const引用的重载。另一方面,代理是临时的,因此不能通过非const引用传递。这让我陷入了两次重载。
我有什么遗失的吗?
后备解决方案类似于:
template < typename PixelReference >
struct Incrementer {
void operator()( PixelReference p ) {
p = p + 1;
}
};
std::for_each( container.begin(), container.end(),
Incrementer< pixel_traits<Pixel,Format>::reference >() );
(假设我有一个像素的特征类)。现在我必须在创建仿函数时指定引用类型,这通常很麻烦。
我有什么方法可以改进其中任何一种选择吗?我正在把这个容器写成一个库,所以我试着尽可能简单地编写和使用仿函数。
感谢。
答案 0 :(得分:2)
使用std::for_each()
可能会阻碍您。如果您使用std::transform()
而该怎么办?它甚至支持相同的就地修改:
transform( container.begin(), container.end(), container.begin(), Incrementer() );
然后Incrementer::operator()
只需要为值传递实现,因为它将不再显式地修改像素。当然,您需要支持为迭代器分配代理值,但也许这并不困难。
答案 1 :(得分:0)
我认为有几种方法可以解决您的问题。
1.在您的示例中,两个operator()
都是相同的,因此您已经在使用编译时多态,而您的问题是operator()
的多重定义
编辑:
代码应如下所示:
struct Incrementer {
template <typename Pixel_or_Proxy>
void operator()( Pixel_or_Proxy& p ) {
p = p + 1;
}
};
2.使用boost enable_if & disable_if并在boost.mpl BOOST_MPL_HAS_XXX_TRAIT_DEF的帮助下检查value_type
3.如果你的代理是一个模板,你可以为它创建一个更好的重载:
template<class T>
void operator()(T t) {
// normal operation
}
template<class T>
void operator()(Proxy<T> t) {
// proxy operation
}
修改:
选项2:由于方法的主体相等,您只需编写一个模板方法。类型名Pixel
和Proxy
只是名称,对编译器没有任何语义含义,只对用户有意义。编译器只是用给定的类型实例化模板方法。如果你有不同的方法,你需要通过重载选择其中一个。这可以通过enable_if和朋友或额外的call with help of type traits完成。