Last resort/catch-all/fallback template overload

If you're willing to require your users to provide their customization points via Argument Dependent Lookup (ADL), you can accomplish this with the proverbial additional layer of indirection. First, it is possible to determine if ADL for a given name succeeds by providing the worst possible fallback and determining if name lookup selects it[*]:

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>()))>;
}

Since the ellipsis conversion is strictly worse than either a standard or user-defined conversion sequence per [over.ics.rank]/2, any reasonable customization of foo provided by the library user will be a better match.

You then need some machinery to dispatch between your fallback implementation and a user-provided customization on the basis of the 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));
}

Users can then provide their customizations fairly simply - simple compared to specializing templates in your library namespace, anyway - by declaring foo overloads in the namespace of their class declarations where ADL can find them (DEMO):

struct UserType {};
struct DerivedUserType : UserType {};

void foo(const UserType&) {
  std::cout << "User extension\n";
}

[*]: ADL Detection technique adapted from @T.C.'s answer to What is a proper way to implement is_swappable to test for the Swappable concept?.


The only parameter guaranteed to have lower precedence than anything else are C-style variadics: ..., and that is certainly not what you'd want (or even be able to) use.

I am afraid there is nothing to provide where the only user-side customisation would be providing an overload. If you can tolerate a little bit higher burden on the user, though, you could make it work with a trait class:

template <class T>
struct HasCustomFoo : std::false_type
{};

template <class T, class Sfinae = typename std::enable_if<!HasCustomFoo<T>::value>::type>
void foo(const T &) { /* Do something generic */}

Then, the user of the library must specialise HasCustomFoo for all applicable classes:

template <>
struct HasCustomFoo<UserBaseType> : std::true_type
{};

template <>
struct HasCustomFoo<UserDerivedType> : std::true_type
{};

void foo(const UserBaseType &) { /* Do something user-specific */ }

foo(UserDerivedType()); // This now calls the user-specific function

It's not fully automatic, but at least the solution is in the user's hands and the library can remain generic.