如果您愿意要求您的用户通过以下方式提供他们的定制点参数相关查找 (ADL) http://en.cppreference.com/w/cpp/language/adl,您可以通过众所周知的附加间接层来实现这一点。首先,可以通过提供最坏的可能回退并确定名称查找是否选择它来确定给定名称的 ADL 是否成功[*]:
namespace detail {
// Simple trait that computes the inverse of std::is_same
template <typename, typename>
struct is_different : std::true_type {};
template <typename T>
struct is_different<T, T> : std::false_type {};
// The ellipsis conversion is worse than any other
// conversion, so overload resolution will choose
// this declaration of foo only if there is no
// result from ADL.
struct tag;
tag foo(...);
// Trait that determines if ADL for foo(T) succeeds.
template <typename T>
using has_adl_foo =
is_different<tag,decltype(foo(std::declval<T>()))>;
}
由于省略号转换严格比每个 [over.ics.rank]/2 的标准或用户定义的转换序列更差,因此任何合理的定制foo
图书馆用户提供的会是更好的匹配。
然后,您需要一些机制在后备实现和用户提供的基于has_adl_foo
trait:
namespace detail {
// Fallback, used only if ADL fails.
template <typename T>
typename std::enable_if<!has_adl_foo<T>::value>::type
impl(T&&) {
std::cout << "Fallback\n";
}
// Dispatch to foo found by ADL.
template <typename T>
typename std::enable_if<has_adl_foo<T>::value,
decltype(foo(std::declval<T>()))
>::type
impl(T&& t) {
return foo(std::forward<T>(t));
}
}
template <typename T>
auto foo(T&& t) ->
decltype(detail::impl(std::forward<T>(t))) {
return detail::impl(std::forward<T>(t));
}
然后,用户可以相当简单地提供他们的自定义 - 无论如何,与库命名空间中的专用模板相比,简单 - 通过声明foo
在其类声明的命名空间中重载,ADL 可以在其中找到它们(DEMO http://coliru.stacked-crooked.com/a/2eab8717786a6d8c):
struct UserType {};
struct DerivedUserType : UserType {};
void foo(const UserType&) {
std::cout << "User extension\n";
}
[*]: ADL Detection technique adapted from @T.C.'s answer https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept/26852703#26852703 to What is a proper way to implement is_swappable to test for the Swappable concept? https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept.