检测功能失败static_assert的习惯用法

SU3*_*SU3 6 c++ static-assert sfinae c++14

有没有办法使用检测习惯用法(或另一种方法)来测试一个函数是否对给定的模板参数有效,如果它由于static_assert?而失败?

下面的例子说明了foo(失败的返回类型计算)的有效性是按预期检测到的,但是bar(失败的static_assert)的有效性则没有.

#include <iostream>
#include <type_traits>

template <typename... T> using void_t = void;

template <class AlwaysVoid, template<class...> class Op, class... Args>
struct detector: std::false_type { };

template <template<class...> class Op, class... Args>
struct detector<void_t<Op<Args...>>, Op, Args...>: std::true_type { };

template <template<class...> class Op, class... Args>
constexpr bool is_detected = detector<void, Op, Args...>::value;

template <typename T>
std::enable_if_t<!std::is_void<T>::value> foo() {
  std::cout << "foo" << std::endl;
}

template <typename T>
void bar() {
  static_assert( !std::is_void<T>::value );
  std::cout << "bar" << std::endl;
}

template <typename T> using foo_t = decltype(foo<T>());
template <typename T> using bar_t = decltype(bar<T>());

int main(int argc, char* argv[]) {

  foo<int>();
  // foo<void>(); // fails as expected

  bar<int>();
  // bar<void>(); // fails as expected

  std::cout << std::boolalpha;

  // detection works for foo
  std::cout << is_detected<foo_t,int > << std::endl; // true
  std::cout << is_detected<foo_t,void> << std::endl; // false

  // but not for bar
  std::cout << is_detected<bar_t,int > << std::endl; // true
  std::cout << is_detected<bar_t,void> << std::endl; // true !!!
}
Run Code Online (Sandbox Code Playgroud)

这就是我无法检测a boost::lexical_cast是否对给定类型有效的原因.

And*_*dyG 6

这里不可能使用SFINAE来获得正确的输出,因为SFINAE规则声明而不是定义进行操作.

bar声明的类型将始终如此void(void),因此就SFINAE而言,声明是可以的.

如果你写了一个真正的检测成语(就像我在这里做的那样),并像这样使用它:

template <typename T> 
using CanCallFoo_t = decltype(&foo<T>);

template<class T>
using CanCallFoo = detect<T, CanCallFoo_t, void>;

template<class T>
using CanCallBar_t = decltype(&bar<T>);

template< class T>
using
CanCallBar = detect<T, CanCallBar_t, void>;

//...
std::cout << CanCallFoo<int>::value << std::endl; // true
std::cout << CanCallFoo<void>::value << std::endl; // false

std::cout << CanCallBar<int>::value << std::endl;
std::cout << CanCallBar<void>::value << std::endl;
Run Code Online (Sandbox Code Playgroud)

您会注意到SFINAE成功,然后在解析定义时出现编译器错误.

错误:静态断言失败
static_assert( !std::is_void<T>::value );

演示

请注意,它的工作原理是foo因为foo声明的类型将使SFINAE失败void

关键static_assert是如果没有找到其他更好的匹配,则编译失败,而不是替换SFINAE.