每当表达式未定义时,在 C++ 中启用函数模板

Enable a function template in C++ whenever an expression is undefined

只要某些表达式被 un 定义(例如,类型 txnot 可流式传输到 std::cout)。像

template<typename t>
auto f(const t &x) 
  -> typename enable_if_undefined<decltype(std::cout << x)>::type;

使用 SFINAE,我只知道如果定义了表达式如何启用,但不知道如果表达式未定义如何启用。

您需要一个助手来提供一个可以反转的布尔值:

template<typename, typename=void>
struct has_cout
    : std::false_type {};

template<typename T>
struct has_cout<T, decltype(std::cout << std::declval<T>(),void())>
    : std::true_type {};

template<typename T>
auto f(const T& x) 
  -> typename std::enable_if<!has_cout<T>::value>::type;

Live example

template<class...>struct types{using type=types;};
namespace details {
  template<template<class...>class Z, class types, class=void>
  struct test_apply:std::false_type{};
  template<template<class...>class Z, class...Ts>
  struct test_apply<Z,types<Ts...>,std::void_t<Z<Ts...>>>:
    std::true_type
  {};
};
template<template<class...>class Z, class...Ts>
using test_apply=details::test_apply<Z,types<Ts...>>;

是元编程样板文件。

那么实际的用例特定代码真的很干净。首先,一个简单的 decltype 别名:

template<class X>
using cout_result = decltype( std::cout << std::declval<X>() );

然后我们对其进行测试:

template<class X>
using can_cout_stream = test_apply< cout_result, X >;

这里的目标是将元编程样板文件与实际使用分离。

template<class T>
std::enable_if_t<!can_cout_stream<const T&>{}>
f(const T& x) 

我自由地使用 C++14 特性来使事情变得更干净。如果您的编译器没有它们,它们都可以在 C++11 中轻松(重新)实现。

template<bool b, class T=void>
using enable_if_t=typename std::enable_if<b,T>::type;
template<class...>struct voider{using type=void;};
template<class...Ts>using void_t=typename voider<Ts...>::type;

应该覆盖它。