我有兴趣了解哪些模板可以用作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
?
答案 0 :(得分:4)
is_detected
旨在与别名模板一起使用,这些模板在使用&#34;错误&#34;进行实例化时会导致直接上下文中的错误(即,SFINAE友好)。参数。
这意味着要检测的替换失败需要在别名模板本身中发生,而不是它实例化的某个类模板:
template<class T>
using member_foo_result_t = decltype(std::declval<T>().foo());