确定模板类型正确谓词的方法
假设我有一个如下所示的函数:
template <class In, class In2>
void func(In first, In last, In2 first2);
我希望这个函数调用另一个接受谓词的函数。我最初的本能是做这样的事情:
template <class In, class In2>
void func(In first, In last, In2 first2) {
typedef typename std::iterator_traits<In>::value_type T;
other_func(first, last, first2, std::less<T>());
}
但是有一个问题,如果 In
和 In2
是不同类型的迭代器怎么办?例如,char*
与 int*
。根据哪个是 In
和哪个是 In2
,谓词可能会在比较期间截断值。例如,如果 In
为 char*
,则即使 In2
也会调用 std::less
是一个int*
。
当给定 ::operator<
两个参数时,编译器能够推断出正确的类型并且应用标准类型提升规则。但是,当选择要传递给函数的谓词时,没有机会发生这种情况。 是否有一些聪明的方法可以根据 In
和 In2
std::less<> >?
编辑:
下面的例子说明了问题:
unsigned int x = 0x80000000;
unsigned char y = 1;
std::cout << std::less<unsigned char>()(x, y) << std::endl;
std::cout << std::less<unsigned int>()(x, y) << std::endl;
将输出:
1
0
编辑:
经过思考,我真正想要的是能够做像这样的东西:
typedef typeof(T1() < T2()) T;
other_func(first, last, first2, std::less<T>());
我想我可以使用 gcc 的 __typeof__ 扩展...,但我也不喜欢这个想法。有什么方法可以以标准一致的方式获得净效果吗?
Suppose I have a function which looks like this:
template <class In, class In2>
void func(In first, In last, In2 first2);
I would like this function to call another function which accepts a predicate. My initial instinct was to do something like this:
template <class In, class In2>
void func(In first, In last, In2 first2) {
typedef typename std::iterator_traits<In>::value_type T;
other_func(first, last, first2, std::less<T>());
}
But there is a problem, what if In
and In2
are iterators to different types? For example, char*
vs int*
. Depending on which is In
and which is In2
the predicate may be truncating values during its comparison. For example, if In
is char*
then std::less<char>
will be called even if In2
is an int*
.
When ::operator<
is given two parameters, the compiler is able to deduce the correct type and the standard type promotion rules apply. However, when selecting a predicate to pass to a function, there is no oportunity to have this happen. Is there some clever way to figure out which version of std::less<>
I want to pass based on In
and In2
?
EDIT:
The following example illustrates the problem:
unsigned int x = 0x80000000;
unsigned char y = 1;
std::cout << std::less<unsigned char>()(x, y) << std::endl;
std::cout << std::less<unsigned int>()(x, y) << std::endl;
will output:
1
0
EDIT:
After thinking about it, what I would really like is to be able to do something like this:
typedef typeof(T1() < T2()) T;
other_func(first, last, first2, std::less<T>());
I suppose I could use gcc's __typeof__
extension..., but I don't love that idea either. Any way to get that net effect in a standard conformant way?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我似乎记得 boost 中有一个特性,但我很快就找不到它搜索。如果您不比我成功,您可以自己构建它,
但您必须指定相当多的明确的专业化。 boost 的 类型特征 库也许可以帮助您减少它们的数量。
编辑:我觉得很愚蠢,操作需要这种东西(结果类型取决于操作数类型),但谓词不需要(结果类型为 bool )。你可以简单地写:
I seemed to remember that there was a traits for this in boost, but I can't find it after a quick search. If you are no more successful than me, you can construct it yourself,
but you'll have to specify quite a few explicit specializations. The type traits library of boost can perhaps help you reduce their number.
Edit: I feel stupid, such kind of things are needed for operation (where the result type depend on the operands types), but not for predicates (where the result type is
bool
). You can simply write:如果您对算法的要求是
In
的value_type
不需要与In2
的值类型相同,那么我会离开您拥有的模板参数;否则它们应该是相同的。无论它们相同还是不同,都取决于您的例程的客户端是否满足算法的先决条件,您可以指定这些先决条件。例如,此处您可能要求
In
的value_type
与In2
的value_type
相同。如果这是正确的,那么该函数应该编译并且按照客户的期望是正确的。在这种情况下,您可以传递任一模板类型的
value_type
的std::less
实例,应该没问题。但是,如果客户端违反了该前提条件(如上面提供的示例,其中
char
与int
不同),那么这将取决于客户端,而不是客户端你,纠正编译时错误。至少可以说,确保您的算法有详细记录:)
If your requirements on the algorithm are such that
In
'svalue_type
need not be the same asIn2
's value type, then I would leave the template parameters as you have them; otherwise they should be the same.Whether they are the same or different it is up to the client of your routine to meet the prerequisites of the algorithm, which you are allowed to specify. For example, here you could require that the
value_type
ofIn
be the same as thevalue_type
ofIn2
. If that holds true, then, the function should compile and be correct as the client expects.In such a case, then, you can pass a
std::less<T>
instance of thevalue_type
of either template type, and you should be fine.However, if the client violates that precondition (as in the example you provide above where
char
is not the same asint
), then it will be up to the client, not you, to correct the compile-time error.Make sure your algorithm is well-documented, to say the least :)
以 SGI 的
std::equal
旧实现为例,STL 算法通过使用同一算法的两个版本来处理这种情况:一个使用内部<
编译器在编译时推导的运算符,以及采用用户定义的二进制谓词的运算符,以便用户可以使用他们喜欢的任何类型:(注意:旧的 SGI STL 代码取自 此处。)
Taking SGI's old implementation of
std::equal
as an example, STL algorithms handle this kind of situation by having two versions of the same algorithm: one that uses the intrinsic<
operator which the compiler deduces at compile time, and one that takes a user-defined binary predicate so the user can use any types they'd prefer:(Note: Old SGI STL code taken from here.)