最后手段/ catch-all / fallback模板超载 [英] Last resort/catch-all/fallback template overload

查看:189
本文介绍了最后手段/ catch-all / fallback模板超载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

正如我先前问过的问题显而易见的,
重载分辨率,模板和继承,将在需要基于转换的过载之前选择模板重载。

As is evident in a question I asked previously, Overload resolution, templates and inheritance, a template overload will be chosen before an overload which requires derived-to-base conversion.

但是,有一种方法提供回退超载,只有选择作为绝对最后的手段,如果没有其他匹配的东西?在这种特殊情况下,可以使用 enable_if ,但不可扩展。不幸的是。

However, is there a way to provide a fallback overload which is only selected as an absolute last resort if there is nothing else that matches? In this particular case enable_if could be used but that would not be extensible, unfortunately.

p>

Like this:

// My library has this and has no knowledge of the possible overloads of foo
template<typename T>
void foo(const T &) { /* Do something */ }

// The user of the library provides this:
void foo(const UserBaseType &) { /* Do something */ }

// User calls foo with object derived from UserBaseType:
foo(UserDerivedType());

在这种情况下,我想调用UserBaseType重载,而不是模板重载。

In this case, I want the UserBaseType overload to be called, not the template overload.

推荐答案

如果您愿意要求用户通过参数依赖查找(ADL),您可以使用谚语的附加层间接来实现。首先,可以通过提供最差的可能回退并确定名称查找是否选择其[*]来确定给定名称的ADL是否成功:

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

由于省略号转换比标准或用户定义的转换序列每[over.ics.rank] / 2,由库用户提供的 foo 的任何合理的定制将是更好的匹配。

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.

然后,您需要一些机制,根据 has_adl_foo trait:

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

用户可以相当简单地提供自定义 - 通过在它们的类声明的命名空间中声明 foo 重载,ADL可以找到它们( DEMO ):

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检测技术改编自 @ TC的回答什么是实现 is_swappable 以测试可交换概念的正确方法? / a>。


[*]: 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?.

这篇关于最后手段/ catch-all / fallback模板超载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆