不使用decltype复制相同行为

问题描述

以下代码可用于快速调试。它可以打印来自STL的矢量之类的漂亮容器,同时还可以使用SFINAE技术为基本类型和可流类型提供打印性属性

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

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)。