不使用 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 {};
您可以使用的其他关键字包括 alignof
、noexcept
、typeid
和 explicit
(自 C++20 以来的最后一个)。
本质上,你想执行表达式SFINAE,这需要构造一个不被评估的表达式。 operators that allow constructing unevaluated expressions 是上面提到的加上 decltype
(您不想使用)和 requires
(C++20)。
下面的代码有助于快速调试。它可以像来自 STL 的矢量一样漂亮地打印容器,同时还能够使用 SFINAE 技术为基本类型和可流式传输类型提供打印性 属性。
我想在不使用 decltype
的情况下复制相同的行为。对于我想到的一些项目,任何其他复制此行为的巧妙技术都将在实现方面非常有帮助。当前线程也可以被视为 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 {};
您可以使用的其他关键字包括 alignof
、noexcept
、typeid
和 explicit
(自 C++20 以来的最后一个)。
本质上,你想执行表达式SFINAE,这需要构造一个不被评估的表达式。 operators that allow constructing unevaluated expressions 是上面提到的加上 decltype
(您不想使用)和 requires
(C++20)。