根据某个函数是否存在启用模板

Enable a template depending on whether a certain function exists

本文关键字:存在 启用 是否 函数      更新时间:2023-10-16

我想设计一个模板,为T::print_to(std::ostream&)存在且可以调用的所有类T自动提供operator<<(std::ostream&, const T&),这样我就可以将打印函数定义为成员函数(尤其是利用虚拟调用(。

经过反复试验,我终于得出了这个结论:

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可以获得更好的解决方案,那么我也对此感兴趣。

在我看来,您在operator<<()中正确应用了SFINAE;我看不出你的解决方案中有陷阱。

我提出了另一个版本(兼容C++11,也兼容C++14(,只是因为需要更少的打字

template <typename T>
auto operator<< (std::ostream & s, T const & t)
-> decltype( t.print_to(s), s )
{
t.print_to(s);
return s;
}

编辑:

你的代码没有任何漏洞,很抱歉。但这个答案使您能够编写更像C++20concept:的代码

template <class T>
auto& operator << (std::ostream &out, const printable_t<T> &t)
{
t.print_to(out);
return out;
}

事实上,我在detector的基础上编写了一个C++17concept_check库,可以这样使用。

有关C++20concept支持的更多信息,请查看以下2:约束和概念(自c++20以来(以及约束和概念

原始答案:

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