我想设计一个模板,为存在operator<<(std::ostream&, const T&)
并且可以调用的所有类T
自动提供一个T::print_to(std::ostream&)
,这样我就可以将打印功能定义为成员函数(尤其是利用虚拟调用)。
通过反复试验,我设法做到了:
template<typename T, typename = decltype(std::declval<T>().print_to(std::declval<std::ostream&>()))>
std::ostream &operator<<(std::ostream &s, const T &t) {
t.print_to(s);
return s;
}
它似乎正在工作,但是由于我还是SFINAE的新手,所以我想知道是否可以进行任何陷阱或改进。我在https://ideone.com/uLJxac放置了一个小型测试台。
如果可能的话,我想拥有一个C ++ 14解决方案,因为我正在使用C ++ 14代码库。但是,如果使用C ++ 17可以提供更好的解决方案,那么对此我也很感兴趣。
答案 0 :(得分:5)
在我看来,您在template <typename T>
auto operator<< (std::ostream & s, T const & t)
-> decltype( t.print_to(s), s )
{
t.print_to(s);
return s;
}
中正确地应用了SFINAE;在您的解决方案中我看不到任何陷阱。
我提议另一个版本(兼容C ++ 11,所以也兼容C ++ 14)
[results[i:i+3] for i in range(0,len(results),3)]
答案 1 :(得分:1)
编辑:
您的代码没有陷阱,对此感到抱歉。但是,这个答案使您可以编写更像C++20
concept
的代码:
template <class T>
auto& operator << (std::ostream &out, const printable_t<T> &t)
{
t.print_to(out);
return out;
}
实际上,我基于C++17
编写了一个detector
concept_check库,并且可以通过这种方式使用。
有关concept
支持C++20
的更多信息,请查看以下2:Constraints and concepts (since c++20)和Constraints and concepts (TS)
原始答案:
std::experiment::is_detector可以为您做魔术。尽管它不在标准库中,但实现起来并不困难,该链接给出了建议的实现。
在这里,我将向您介绍如何检测该功能以及我的is_detected_v
的实现。
#include <type_traits>
#include <utility>
#include <ostream>
// For support for C++17 is not complete in many compiler, I also define void_t
template <class...> using void_t = void;
namespace impl {
template <class Default, class AlwaysVoid, template <class...> class Op, class ...Args>
struct detector: private std::false_type
{
using std::false_type::value;
using type = Default;
};
template <class Default, template <class...> class Op, class ...Args>
struct detector<Default, void_t<Op<Args...>>, Op, Args...>: private std::true_type
{
using std::true_type::value;
using type = Op<Args...>;
};
} // namespace impl
struct nonsuch {};
#define CONCEPT_T constexpr const static inline bool
template <template<class...> class Op, class ...Args>
CONCEPT_T is_detected_v = impl::detector<nonsuch, void, Op, Args...>::value;
// Detect whether print_to exists.
template <class T>
using print_to_ret_t = decltype( std::declval<T>().print_to( std::declval<std::ostream&>() ) );
template <class T>
CONCEPT_T has_func_print_to_v = is_detected_v<print_to_ret_t, T>;
template <class T, std::enable_if_t< has_func_print_to_v<T> >>
using printable_t = T;
#undef CONCEPT_T
您可以尝试向此代码添加C++14
支持。不会太困难。必须将CONCEPT_T
更改为constexpr const static bool
才能调整为C++14
。