定义交换操作时减less代码重复

我有一套名为overlap的可交换二元函数的重载,它接受两种不同的types:

 class A a; class B b; bool overlap(A, B); bool overlap(B, A); 

当且仅当一个形状与另一个形状重叠时,我的函数overlap返回true – 这是讨论多方法时使用的一个常见示例。

因为overlap(a, b)等价于overlap(b, a) ,所以我只需要实现关系的一个“边”。 一个重复的解决scheme是写这样的东西:

 bool overlap(A a, B b) { /* check for overlap */ } bool overlap(B b, A a) { return overlap(a, b); } 

但我宁愿不写一个额外的N! / 2 N! / 2相同function的简单版本,通过使用模板来生成它们。

 template <typename T, typename U> bool overlap(T&& t, U&& u) { return overlap(std::forward<U>(u), std::forward<T>(t)); } 

不幸的是,这是容易无限递增,这是不可接受的:见http://coliru.stacked-crooked.com/a/20851835593bd557

我怎样才能防止这种无限recursion? 我是否正确地处理了这个问题?

这是一个简单的修复:

 template <typename T, typename U> void overlap(T t, U u) { void overlap(U, T); overlap(u, t); } 

模板本身声明了目标函数,它比recursion更受欢迎,因为它是完全匹配的(确保在实际情况下处理常量和引用)。 如果函数没有被执行,你会得到一个链接器错误:

 /tmp/cc7zinK8.o: In function `void overlap<C, D>(C, D)': main.cpp:(.text._Z7overlapI1C1DEvT_T0_[_Z7overlapI1C1DEvT_T0_]+0x20): undefined reference to `overlap(D, C)' collect2: error: ld returned 1 exit status 

…直接指向缺less的function:)

正如一位智者曾经说过的那样,除了太多的间接层之外,没有什么问题可以通过额外的间接层解决。

所以,使用SFINAE和一些间接的方法来完成它:

 template<class A, class B> auto overlap(A&& a, B&& b) -> decltype(overlap_impl('\0', std::forward<A>(a), std::forward<B>(b))) { return overlap_impl('\0', std::forward<A>(a), std::forward<B>(b)); } template<class A, class B> auto overlap_impl(int, A&& a, B&& b) -> decltype(do_overlap(std::forward<A>(a), std::forward<B>(b))) { return do_overlap(std::forward<A>(a), std::forward<B>(b)); } template<class A, class B> auto overlap_impl(long, B&& b, A&& a) -> decltype(do_overlap(std::forward<A>(a), std::forward<B>(b))) { return do_overlap(std::forward<A>(a), std::forward<B>(b)); } // You can provide more choices if you want, for example to use member-functions. // Implement `do_overlap(A, B)`, maybe with references, in at least one direction. 

您可以将实际的方法重命名为overlap_impl并在模板内调用此方法。 我将打破recursion:

 bool overlap_impl(A a, B b) { /* check for overlap */ } template <typename T, typename U> bool overlap(T&& t, U&& u) { return overlap_impl(std::forward<U>(u), std::forward<T>(t)); } template<> bool overlap(A&& t, B&& u) { return overlap_impl(std::forward<A>(t), std::forward<B>(u)); }