根据是否存在某个功能启用模板

时间:2018-10-27 14:28:58

标签: c++ templates operator-overloading c++14 sfinae

我想设计一个模板,为存在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可以提供更好的解决方案,那么对此我也很感兴趣。

2 个答案:

答案 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