使用可变函数参数泛化 is_detected
Generalizing is_detected with variadic function parameters
我正在尝试修改 is_detected
习语以允许向其传递可变参数。我需要这个,因为我检测到的一些成员函数将有用户提供的参数。
到目前为止,这就是我的工作。您将额外的参数提供给 is_detected_args_v
,理论上,模板特化会启动并正确编译。因此给出 std::true_type
.
#include <type_traits>
#include <cstdio>
// slightly modified (and simplified) is_detected
template <template <class, class...> class Op, class T, class = void, class...>
struct is_detected_args : std::false_type {};
template <template <class, class...> class Op, class T, class... Args>
struct is_detected_args<Op, T, std::void_t<Op<T, Args...>>, Args...>
: std::true_type {};
template <template <class, class...> class Op, class T, class... Args>
inline constexpr bool is_detected_args_v
= is_detected_args<Op, T, Args...>::value;
// has_func, checks the function starts with int, and then Args&...
template <class T, class... Args>
using has_func = decltype(std::declval<T>().func(
std::declval<int>(), std::declval<Args&>()...));
// has the func
struct obj {
void func(int, double&, double&) {
printf("potato\n");
}
};
int main(int, char**) {
obj o;
if constexpr(is_detected_args_v<has_func, obj, double, double>) {
double d = 0;
double d2 = 42;
o.func(42, d, d2);
}
}
您可以 运行 这里的示例(在所有 3 个编译器上测试):https://wandbox.org/permlink/ttCmWSVl1XVZjty7
问题是,从未选择专业化,条件始终为假。我的问题有两个。
- 这可能吗?
- 为什么
is_detected
没有专业化?
感谢
这里的主要问题是误解了 void_t
的作用。作为复习,请参阅 how does void_t
work?。关键思想是主模板有一个 void
参数,并且特化有一些复杂的东西,你想检查包裹在 void_t
中,以便它 匹配 主模板的参数。在您的示例中没有发生这种情况。
我们可以通过两个简单的步骤修复它。首先,你有这个类型 T
和 Args...
实际上没有任何理由把它分开,如果我们没有无关的参数,它会更容易看。所以这是你的尝试只是减少了(我也给了一个应该是 void
的参数的名字):
template <template <class...> class Op, class AlwaysVoid, class...>
struct is_detected_args : std::false_type {};
template <template <class...> class Op, class... Args>
struct is_detected_args<Op, std::void_t<Op<Args...>>, Args...>
: std::true_type {};
template <template <class...> class Op, class... Args>
inline constexpr bool is_detected_args_v = is_detected_args<Op, Args...>::value;
现在应该更容易看出缺少什么:void
参数!您没有传递 void
而您需要传递。不过这很容易修复:
template <template <class...> class Op, class... Args>
inline constexpr bool is_detected_args_v = is_detected_args<Op, void, Args...>::value;
// ~~~~~
现在它按预期工作了。
Cppreference 还提供了 is_detected
的完整实现,如果您也想查看的话。
我正在尝试修改 is_detected
习语以允许向其传递可变参数。我需要这个,因为我检测到的一些成员函数将有用户提供的参数。
到目前为止,这就是我的工作。您将额外的参数提供给 is_detected_args_v
,理论上,模板特化会启动并正确编译。因此给出 std::true_type
.
#include <type_traits>
#include <cstdio>
// slightly modified (and simplified) is_detected
template <template <class, class...> class Op, class T, class = void, class...>
struct is_detected_args : std::false_type {};
template <template <class, class...> class Op, class T, class... Args>
struct is_detected_args<Op, T, std::void_t<Op<T, Args...>>, Args...>
: std::true_type {};
template <template <class, class...> class Op, class T, class... Args>
inline constexpr bool is_detected_args_v
= is_detected_args<Op, T, Args...>::value;
// has_func, checks the function starts with int, and then Args&...
template <class T, class... Args>
using has_func = decltype(std::declval<T>().func(
std::declval<int>(), std::declval<Args&>()...));
// has the func
struct obj {
void func(int, double&, double&) {
printf("potato\n");
}
};
int main(int, char**) {
obj o;
if constexpr(is_detected_args_v<has_func, obj, double, double>) {
double d = 0;
double d2 = 42;
o.func(42, d, d2);
}
}
您可以 运行 这里的示例(在所有 3 个编译器上测试):https://wandbox.org/permlink/ttCmWSVl1XVZjty7
问题是,从未选择专业化,条件始终为假。我的问题有两个。
- 这可能吗?
- 为什么
is_detected
没有专业化?
感谢
这里的主要问题是误解了 void_t
的作用。作为复习,请参阅 how does void_t
work?。关键思想是主模板有一个 void
参数,并且特化有一些复杂的东西,你想检查包裹在 void_t
中,以便它 匹配 主模板的参数。在您的示例中没有发生这种情况。
我们可以通过两个简单的步骤修复它。首先,你有这个类型 T
和 Args...
实际上没有任何理由把它分开,如果我们没有无关的参数,它会更容易看。所以这是你的尝试只是减少了(我也给了一个应该是 void
的参数的名字):
template <template <class...> class Op, class AlwaysVoid, class...>
struct is_detected_args : std::false_type {};
template <template <class...> class Op, class... Args>
struct is_detected_args<Op, std::void_t<Op<Args...>>, Args...>
: std::true_type {};
template <template <class...> class Op, class... Args>
inline constexpr bool is_detected_args_v = is_detected_args<Op, Args...>::value;
现在应该更容易看出缺少什么:void
参数!您没有传递 void
而您需要传递。不过这很容易修复:
template <template <class...> class Op, class... Args>
inline constexpr bool is_detected_args_v = is_detected_args<Op, void, Args...>::value;
// ~~~~~
现在它按预期工作了。
Cppreference 还提供了 is_detected
的完整实现,如果您也想查看的话。