首页 > 解决方案 > 就 SFINAE 而言,访问不存在的成员是否不被视为“错误”?

问题描述

我已经为漂亮的打印对实现了重载:

template<typename P>
ostream &operator<<(ostream &os, const P &p) {
  using std::operator<<;
  os << '(' << p.first << ", " << p.second << ')';
  return os;
}

然而,在它存在的情况下,编译器很难判断它应该应用标准重载还是我上面定义的重载,即使在选择应该很明显的情况下:

int main() {
  cout << "SFINAE sure is hard to grasp!\n";
}

error: use of overloaded operator '<<' is
      ambiguous (with operand types 'std::ostream' (aka 'basic_ostream<char>') and
      'const char [30]')

我不太明白问题是什么。我试图打印的 char 数组显然没有firstorsecond成员,所以用我的重载实例化它会导致错误。

SFINAE 不应该尝试执行替换,找出缺少成员并丢弃结果吗?如果不是,为什么?

标签: c++templatessfinae

解决方案


SFINAE在过载解决期间工作:

此规则适用于函数模板的重载解析:当用显式指定或推导的类型替换模板参数失败时,特化将从重载集中丢弃,而不是导致编译错误。

这意味着只有函数模板的签名才会对 SFINAE 生效,不会检查实现。

您可以将重载更改为

template <typename T, typename = void>
struct pairable : std::false_type {};

// check whether type T has first and second members
template <typename T>
struct pairable<T, std::void_t<decltype(std::declval<T>().first),
                               decltype(std::declval<T>().second)>>
    : std::true_type {};

// the template parameter is the part of the signature of function template
template<typename P, std::enable_if_t<pairable<P>::value>* = nullptr>
ostream &operator<<(ostream &os, const P &p) {
  using std::operator<<;
  os << '(' << p.first << ", " << p.second << ')';
  return os;
}

居住


推荐阅读