SFINAE过载运算符<<致电'打印'方法是否存在

时间:2015-01-20 00:07:49

标签: c++ sfinae

我一直试图了解SFINAE,并试图编写一个简单的重载运算符<<这将打电话给'打印'包含这种方法的任何类的方法。我仔细阅读了问题Is it possible to write a template to check for a function's existence?的答案并尝试写作:

template<class T, class = decltype(void(std::declval<T>().print), std::true_type{})>
inline std::ostream &operator<<(std::ostream &out, const T &obj) {
    obj.print(out); return out; }

template<class T, class = decltype(void(std::declval<T>().print(std::declval<std::ostream &>())), std::true_type{})>
inline std::ostream &operator<<(std::ostream &out, const T &obj) {
    obj.print(out); return out; }

但这根本不起作用 - 编译器似乎没有问题为任何类型实例化模板,因此给出了一些模糊的过载&#39;当我尝试打印像字符串文字这样的东西时出错......

2 个答案:

答案 0 :(得分:1)

您的“功能存在”表达式不正确。试试这个:

template <typename T,
          typename = decltype(
               void(std::declval<T>().print(std::declval<std::ostream&>())),
                    std::true_type{})>  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
std::ostream & operator<<(std::ostream & out, const T & obj)
{
    obj.print(out);
    return out;
}

你也可以考虑这个选择:

template <typename T>
auto operator<<(std::ostream & out, const T & obj)
     -> decltype(obj.print(out), (void)0, out)
{
    obj.print(out);
    return out;
}

答案 1 :(得分:0)

我不明白你的第二种类型参数

class = decltype(void(std::declval<T>().print), std::true_type{})

意思是。这应该评估什么?

我认为您可以使用以下内容使其正常工作。

#include <iostream>
#include <type_traits>

template<typename T,
         typename = decltype(std::declval<const T>().print(std::cout))>
std::ostream&
operator<<(std::ostream& out, const T& obj)
{
  obj.print(out);
  return out;
}

struct A
{
  void
  print(std::ostream& out) const
  {
    out << "A";
  }
};

int
main()
{
  A a {};
  std::cout << "And the winner is: " << a << std::endl;
}

它会正确输出And the winner is: A,但可能会有一些我忽略的极端情况。

表达式

decltype(std::declval<const T>().print(std::cout))
如果声明了这样的函数,

将评估print(std::ostream&) const成员函数的返回类型,否则将返回类型错误。