如果类具有特定的成员函数,如何启用函数模板?

问题描述 投票:0回答:1

我编写了以下模板函数,它检查任意容器是否包含特定元素:

template<template<class, class...> class container_t, class item_t, class... rest_t>
bool contains(const container_t<item_t, rest_t...> &_container, const item_t &_item) {
    for(const item_t &otherItem : _container) {
        if(otherItem == _item) { return true; }
    }
    return false;
}

这对于大多数容器都适用。然而,对于所有类型的集合(和地图)来说,它都是次优的,因为我们可以使用:

template<template<class, class...> class set_t, class item_t, class... rest_t>
bool contains(const set_t<item_t, rest_t...> &_set, const item_t &_item) {
    return _set.count(_item) > 0;
}

显然,由于不明确,我们不能同时使用这两个模板。现在我正在寻找一种方法,如果

std::enable_if
不提供
container_t
成员函数,则使用
count
启用第一个模板,如果提供,则使用第二个模板。但是我不知道如何检查特定的成员函数(使用 C++11)。

c++ c++11 sfinae function-templates c++-templates
1个回答
16
投票

C++14 功能,重新实现:

template<class...>struct voider{using type=void;};
template<class...Ts>using void_t=typename voider<Ts...>::type;

一个迷你元编程库:

template<class...>struct types{using type=types;};
namespace details {
  template<template<class...>class Z, class types, class=void>
  struct can_apply : std::false_type {};
  template<template<class...>class Z, class...Ts>
  struct can_apply< Z, types<Ts...>, void_t< Z<Ts...> > >:
    std::true_type
  {};
}
template<template<class...>class Z, class...Ts>
using can_apply = details::can_apply<Z,types<Ts...>>;

can_apply< some_template, args... >
继承自
true_type
当且仅当
some_template<args...>
是一个有效的表达式(在直接上下文中)。

现在解决你的问题:

template<class T, class I>
using dot_count_type = decltype( std::declval<T>().count(std::declval<I>()) );

template<class T, class I>
using has_dot_count = can_apply<dot_count_type, T, I>;

and

has_dot_count
是一个继承自
true_type
的特征类,当且仅当
T.count(I)
是一个有效的表达式。

namespace details {
  template<class C, class I>
  bool contains(std::false_type, C const& c, I const& i) {
    for(auto&& x:c) {
      if(x == i) { return true; }
    }
    return false;
  }
  template<class C, class I>
  bool contains(std::true_type, C const& c, I const& i) {
    return c.count(i) != 0;
  }
}
template<class C, class I>
bool contains( C const& c, I const& i ) {
  return details::contains( has_dot_count<C const&,I const&>{}, c, i );
}

它使用标签调度而不是 SFINAE。

使用

find
似乎比
.count
作为旁白更好。事实上,在一种情况下,您应该使用
.find
,另一种情况下
find
。在这两种情况下,您都应该使用
using std::end; auto e = end(c);

顺便说一句,MSVC 2013(我不知道 2015 年)不处理上面使用的这种 SFINAE。他们称之为“表达 SFINAE”。它们具有自定义扩展来检测成员函数是否存在。但那是因为它们远不符合 C++11 标准。

© www.soinside.com 2019 - 2024. All rights reserved.