如何使用 is_invocable() 创建用于重载<<打印对象的模板?

How can I use is_invocable() to create a template for overloading << for printing out an object?

本文关键字:lt 打印 对象 重载 is 何使用 invocable 用于 创建      更新时间:2023-10-16

我感谢此堆叠式问题的答案,该问题是操作员的通用实现&lt;&lt;根据转储成员功能的功能

但是,理查德·霍奇斯(Richard Hodges)的答案表明,C 17的IS_invocable()可用于简化此解决方案。

当我尝试使用is_invocable()实现解决方案时,我会收到一个编译错误。

我在无需is_invocable调用的情况下有效的代码周围有一个#ifdef 0。有效。

我需要如何更改代码以获取IS_INVOCABLE CALL的工作?

谢谢!

编译错误:

main.cpp:16:46: error: reference to non-static member function must be called
  static_assert(std::is_invocable<decltype(t.dump),
                                           ~~^~~~
main.cpp:47:13: note: in instantiation of function template specialization 'operator<<<Foobar, char>' requested here
  std::cout << foobar << std::endl;
            ^
main.cpp:32:32: note: possible target for call
    std::basic_ostream<charT> &dump(std::basic_ostream<charT> &o) const

代码:

#include <iostream>
#include <string>
#include <type_traits>
template<typename T, typename charT>
auto operator<<(std::basic_ostream<charT> &str, const T &t) -> decltype(t
    .dump(str))
{
#if 0
  static_assert(std::is_same
                    <decltype(t.dump(str)),
                std::basic_ostream<charT> &>::value,
                ".dump(ostream&) does not return ostream& !");
#else
  static_assert(std::is_invocable<decltype(t.dump),
                std::basic_ostream<charT> &>::value,
                ".dump(ostream&) does not return ostream& !");
#endif
  return t.dump(str);
}
class Foobar {
public:
    Foobar(std::string nameArg)
        :
        name(nameArg)
    {}
    template<typename charT>
    std::basic_ostream<charT> &dump(std::basic_ostream<charT> &o) const
    {
      return (o << name);
    }
private:
    std::string name;
};
int main()
{
  Foobar foobar("private name");
  std::cout << foobar << std::endl;
  return 0;
}

根据@oktalist的答案,我对我的代码进行了如下修改。我留下原始代码,因此问题很有意义。修改的代码未编译。我相信我只是错过了如何工作的细微差别。

编译错误是

error: invalid operands to binary expression ('std::__1::ostream' (aka 'basic_ostream<char>') and 'Foobar') std::cout << foobar << std::endl;

这是未编译的更新代码:

#include <iostream>
#include <string>
#include <type_traits>
    template<typename T, typename charT>
auto operator<<(std::basic_ostream<charT> &str, const T &t) ->
  decltype(t.dump)
{
  static_assert(std::is_invocable_r<
      std::basic_ostream<charT> &,  // return type
      decltype(&T::dump),           // invocable type
      T const &,                    // first arg type (implicit this)
      std::basic_ostream<charT> &   // second arg type
    >::value, "dump(ostream&) does not return ostream& !");
  return t.dump(str);
}
class Foobar {
public:
    Foobar(std::string nameArg)
        :
        name(nameArg)
    {}
    template<typename charT>
    std::basic_ostream<charT> &dump(std::basic_ostream<charT> &o) const
    {
      return (o << name);
    }
private:
    std::string name;
};
int main()
{
  Foobar foobar("private name");
  std::cout << foobar << std::endl;
  return 0;
}

首先, decltype(t.dump)是无效的。您想要decltype(&T::dump)

其次,如果要检查返回类型,则需要std::is_invocable_r,并且也需要提供两种参数类型:

static_assert(std::is_invocable_r<
                  std::basic_ostream<charT> &,  // return type
                  decltype(&T::dump),           // invocable type
                  T const &,                    // first arg type (implicit this)
                  std::basic_ostream<charT> &   // second arg type
              >::value, ".dump(ostream&) does not return ostream& !");

在您的情况下,以上是不起作用的,因为 dump是函数模板。

std::is_invocable_r<
    std::basic_ostream<charT> &,
    decltype(&T::template dump<charT>),
    T const &,
    std::basic_ostream<charT> &
>::value

那会起作用,但是您将自己限制在dump的某个签名中,我不知道为什么您认为在这里使用is_invocable是有帮助的。