【问题标题】:Enable a template depending on whether a certain function exists根据是否存在某个功能启用模板
【发布时间】:2018-10-27 14:28:57
【问题描述】:

我想设计一个模板,它自动为所有类T 提供一个operator<<(std::ostream&, const 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 可以提供更好的解决方案,那我也对它感兴趣。

【问题讨论】:

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


【解决方案1】:

在我看来,您在operator&lt;&lt;() 中正确应用了 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;
 }

【讨论】:

  • 这个版本真的很简洁,适合只用一两次的concepts
【解决方案2】:

编辑:

您的代码没有缺陷,对此感到抱歉。但是这个答案可以让你写出更像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++20 中的concept 支持的更多信息,请查看以下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

【讨论】:

  • 对不起,但是……你为什么说 Giuseppe 的 SFINAE 实现是错误的?这对我来说似乎是正确的。
  • @max66 你是对的...抱歉误导性声明。
猜你喜欢
  • 2017-04-03
  • 2012-12-30
  • 2011-09-17
  • 2020-08-05
  • 1970-01-01
  • 1970-01-01
  • 2021-10-26
  • 2014-08-08
  • 1970-01-01
相关资源
最近更新 更多