不使用 decltype 复制相同的行为

Replication of same behaviour without using decltype

下面的代码有助于快速调试。它可以像来自 STL 的矢量一样漂亮地打印容器,同时还能够使用 SFINAE 技术为基本类型和可流式传输类型提供打印性 属性。

我想在不使用 decltype 的情况下复制相同的行为。对于我想到的一些项目,任何其他复制此行为的巧妙技术都将在实现方面非常有帮助。当前线程也可以被视为 线程的延续(也是我认为的)。我设法在 C++20 (GCC 10.2.0) 中使用 concepts 获得了一个简洁的工作实现而不使用 decltype 但我希望能够在 C++17 中这样做( GCC 9.2.0) 及更低版本(显然,没有概念,并且没有提到 decltype)。

namespace debugging {
    template <typename T>
    class range {
      public:
        T begin, end;
    };

    template <typename T>
    auto make_range (const T& b, const T& e) -> range <T> {
        return {b, e};
    }

    template <typename T>
    auto is_streamable_object (T *x) -> decltype(std::cerr << *x, std::true_type());

    template <typename T>
    auto is_streamable_object (...)  -> decltype(std::false_type());

    class view {
      private:
        std::ostream& stream;
      public:
        view (std::ostream& os = std::cerr) : stream (os)
        { };

        ~view ()
        { stream << std::endl; };

  #ifdef LOST_IN_SPACE
        template <typename T>
        std::enable_if_t <std::is_same <decltype(is_streamable_object <T> (nullptr)), std::true_type>::value, view&>
        operator << (const T& t) {
            stream << std::boolalpha << t; return *this;
        }

        template <typename T>
        std::enable_if_t <std::is_same <decltype(is_streamable_object <T> (nullptr)), std::false_type>::value, view&>
        operator << (const T& t) {
            return *this << make_range(begin(t), end(t));
        }

        template <typename T>
        view& operator << (const range <T>& r) {
            stream << "[";
            for (auto i = r.begin, j = i; i != r.end; ++i)
                *this << *i << (++j == r.end ? "]" : ", ");
            return *this;
        }

        template <typename A, typename B>
        view& operator << (const std::pair <A, B>& p) {
            stream << '(' << p.first << ", " << p.second << ')';
            return *this;
        }
  #else
        template <typename T> view& operator << (const T&)
        { return *this; }
  #endif
    };
} // namespace debugging

如果您想自己快速尝试,请测试代码:

#define print(x) " [" << #x << ": " << x << "] "

using view = debugging::view;
view debug (std::cerr);

auto test () -> void {
    std::vector <int> v {1,2,3,4,5};
    std::map <int, int> m {{1,2}, {3,4}};
    debug << print(v) print(m) << "\nHello World";
}

当然,这是一个使用 sizeof:

的实现
template<class T, class = std::false_type>
struct is_streamable_object : std::false_type {};

template<class T>
struct is_streamable_object<T,
    std::bool_constant<sizeof(std::cerr << std::declval<T>()) == 0>> : std::true_type {};

Example.

您可以使用的其他关键字包括 alignofnoexcepttypeidexplicit(自 C++20 以来的最后一个)。

本质上,你想执行表达式SFINAE,这需要构造一个不被评估的表达式。 operators that allow constructing unevaluated expressions 是上面提到的加上 decltype(您不想使用)和 requires (C++20)。