is_detected可以使用哪些模板?

时间:2017-12-18 20:39:59

标签: c++ templates metaprogramming

我有兴趣了解哪些模板可以用作std::experimental::is_detected和类似检测实用程序的第一个参数。

下面粘贴的是is_detected的实现,并尝试使用它来检测类型T是否具有名为.foo()的成员函数。它使用的一般模式是首先定义一个类型特征,它返回成员函数T::foo的类型(如果存在):

template<class T>
struct member_foo_result
{
  using type = decltype(std::declval<T>().foo());
};

然后,它定义了一个速记别名:

template<class T>
using member_foo_result_t = typename member_foo_result<T>::type;

问题是速记别名似乎与is_detected不兼容。

这是完整的程序,带有编译器输出:

#include <utility>
#include <type_traits>
#include <iostream>

// implementation of is_detected
template<class...> 
using void_t = void; 

struct nonesuch 
{ 
  nonesuch() = delete; 
  ~nonesuch() = delete; 
  nonesuch(const nonesuch&) = delete; 
  void operator=(const nonesuch&) = delete; 
}; 


template<class Default, class AlwaysVoid,
         template<class...> class Op, class... Args> 
struct detector 
{ 
  using value_t = std::false_type; 
  using type = Default; 
}; 


template<class Default, template<class...> class Op, class... Args> 
struct detector<Default, void_t<Op<Args...>>, Op, Args...> 
{ 
  using value_t = std::true_type; 
  using type = Op<Args...>; 
}; 
template<template<class...> class Op, class... Args> 
using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t; 



// returns the result type of T::foo()
template<class T>
struct member_foo_result
{
  using type = decltype(std::declval<T>().foo());
};

// shorthand alias for member_foo_result<T>::type
template<class T>
using member_foo_result_t = typename member_foo_result<T>::type;


// detects whether or not the member function T::foo() exists
template<class T>
struct has_foo_member : is_detected<member_foo_result_t, T> {};


struct doesnt_have_foo_member {};


int main()
{
  std::cout << "result: " << has_foo_member<doesnt_have_foo_member>::value << std::endl;
}

我希望这个程序打印出来&#34;结果:0&#34;在运行时。但是,它无法正确编译:

$ clang -std=c++11 test_is_detected.cpp 
test_is_detected.cpp:41:43: error: no member named 'foo' in 'doesnt_have_foo_member'
  using type = decltype(std::declval<T>().foo());
                        ~~~~~~~~~~~~~~~~~ ^
test_is_detected.cpp:45:1: note: in instantiation of template class 'member_foo_result<doesnt_have_foo_member>' requested here
using member_foo_result_t = typename member_foo_result<T>::type;
^
test_is_detected.cpp:27:33: note: in instantiation of template type alias 'member_foo_result_t' requested here
struct detector<Default, void_t<Op<Args...>>, Op, Args...> 
                                ^
test_is_detected.cpp:33:1: note: during template argument deduction for class template partial specialization 'detector<type-parameter-0-0, void, Op, type-parameter-0-2...>' [with Default = nonesuch, Op =
      member_foo_result_t, Args = <doesnt_have_foo_member>]
using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t; 
^
test_is_detected.cpp:50:25: note: in instantiation of template type alias 'is_detected' requested here
struct has_foo_member : is_detected<member_foo_result_t, T> {};
                        ^
test_is_detected.cpp:58:30: note: in instantiation of template class 'has_foo_member<doesnt_have_foo_member>' requested here
  std::cout << "result: " << has_foo_member<doesnt_have_foo_member>::value << std::endl;
                             ^
1 error generated.

我是否误用is_detected

1 个答案:

答案 0 :(得分:4)

is_detected旨在与别名模板一起使用,这些模板在使用&#34;错误&#34;进行实例化时会导致直接上下文中的错误(即,SFINAE友好)。参数。

这意味着要检测的替换失败需要在别名模板本身中发生,而不是它实例化的某个类模板:

template<class T>
using member_foo_result_t = decltype(std::declval<T>().foo());