SFINAE 过载选择有或没有操作员<<

SFINAE overload choice for has or has not operator<<?

本文关键字:操作员 选择 SFINAE      更新时间:2023-10-16

考虑以下两个函数:

template <class Type, 
          class = typename std::enable_if</*HAS OPERATOR <<*/>::type>
void f(std::ostream& stream, const Type& value);
template <class Type, 
          class... DummyTypes,
          class = typename std::enable_if<sizeof...(DummyTypes) == 0>::type>
void f(std::ostream& stream, const Type& value, DummyTypes...);

由于非可变参数重载优先于可变参数重载,因此我想检查该类型是否具有第一个版本中使用 std::enable_ifstd::ostream operator<<

那么我应该写什么而不是/*HAS OPERATOR <<*/

以下内容应该有效

template <class Type, 
          class = decltype(std::declval<std::ostream&>() << std::declval<Type>())>
void f(std::ostream& stream, const Type& value)
{
    stream << value;
}

(请注意,在这种情况下,您不需要使用 std::enable_if

使用尾随返回类型 (1),您实际上可以预感概念:

template <typename Type>
auto f(std::ostream& out, Type const& t) -> decltype(out << t, void()) {
    // ...
}

由于 SFINAE,只有在可以解析out << t类型时才能选择此重载,这意味着存在接受这两个参数的重载 <<

一个陷阱是,如果您需要相反的方法,这将不起作用,即如果此重载不存在,则启用函数。据我所知,在这种情况下,enable_if策略(和对称disable_if)是必要的。

(1)感谢Simple

帮助语法

当你有参数时,检查是最容易的,即,我宁愿尝试使用这样的东西:

template <typename Type>
auto f(std::ostream& out, Type const& value)
    -> typename std::enable_if<sizeof(out << value) != 0>::type {
    ...
}

使用 std::declval() 可以获得类似的效果,但我不确定是否创建引用。