根据某个函数是否存在启用模板
Enable a template depending on whether a certain function exists
我想设计一个模板,为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++20
concept
:的代码
template <class T>
auto& operator << (std::ostream &out, const printable_t<T> &t)
{
t.print_to(out);
return out;
}
事实上,我在detector
的基础上编写了一个C++17
concept_check库,可以这样使用。
有关C++20
中concept
支持的更多信息,请查看以下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
。
- C++模板来检查友元函数的存在
- 编译时未启用intel oneApi CUDA支持
- 既然存在危险,为什么项目要使用-I include开关
- 我们可以访问一个不存在的联盟的成员吗
- C++:对不存在的命名空间使用命名空间指令
- C++quit()函数中可能存在作用域问题
- C++擦除(如果存在)
- OpenGL在启用深度测试时不会丢弃我的碎片
- g++ 说函数不存在,即使包含正确的标头
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 有了gcc,是否可以链接库,但前提是它存在
- Visual C++GC接口如何启用它以及要包含哪个库
- C++LinkedList问题.数据类型之间存在冲突?没有匹配的构造函数
- gcc和clang在表达式是否为常量求值的问题上存在分歧
- C++Builder中的OnClick事件签名存在问题
- 如何正确地将分支添加到已存在的树中
- 如何在自定义类中启用'auto loops'?
- 根据某个函数是否存在启用模板
- 不存在的标识符在非启用函数模板中用作默认参数
- C++仅在不存在时才启用的功能