gpt4 book ai didi

c++ - 使用可变参数测试成员函数是否存在

转载 作者:IT老高 更新时间:2023-10-28 22:40:44 26 4
gpt4 key购买 nike

所以我非常熟悉测试成员函数是否存在的范例。目前此代码有效:

#include <iostream>
#include <type_traits>

struct has_mem_func_foo_impl {
template <typename U, U>
struct chk { };

template <typename Class, typename Arg>
static std::true_type has_foo(chk<void(Class::*)(Arg), &Class::foo>*);

template <typename, typename>
static std::false_type has_foo(...);
};

template <typename Class, typename Arg>
struct has_mem_func_foo : decltype(has_mem_func_foo_impl::template has_foo<Class,Arg>(nullptr)) { };


struct bar {
void foo(int) { }
};

int main() {
static_assert( has_mem_func_foo<bar, int>::value, "bar has foo(int)" );
}

很遗憾,如果我稍微调整一下:

#include <iostream>
#include <type_traits>

struct has_mem_func_foo_impl {
template <typename U, U>
struct chk { };

template <typename Class, typename... Arg>
static std::true_type has_foo(chk<void(Class::*)(Arg...), &Class::foo>*);

template <typename, typename...>
static std::false_type has_foo(...);
};

template <typename Class, typename... Arg>
struct has_mem_func_foo : decltype(has_mem_func_foo_impl::template has_foo<Class,Arg...>(nullptr)) { };


struct bar {
void foo(int) { }
};

int main() {
static_assert( has_mem_func_foo<bar, int>::value, "bar has foo(int)" );
}

我的静态断言失败。我的印象是,可变参数模板参数包在扩展到它们的位置时会得到相同的处理。 gcc 和 clang 都会产生一个失败的静态断言。

因此,我的问题的真正根源是,这是标准行为吗?当测试是否存在可变参数模板化成员函数时,它也会失败。

最佳答案

我看到的问题是 Arg... 被传递 int 是不够的。编译器在其末尾添加新参数是有效的。

不可能从 nullptr_t 推断在其末尾添加的内容,因此编译器会说“我放弃,不是这种情况”。

But we don't need to have Arg... in a deducable context for your trick to work :

#include <iostream>
#include <type_traits>

template<class Sig>
struct has_mem_func_foo_impl;

template<class R, class...Args>
struct has_mem_func_foo_impl<R(Args...)> {
template <typename U, U>
struct chk { };

template <typename Class>
static constexpr std::true_type has_foo(chk<R(Class::*)(Args...), &Class::foo>*) { return {}; }

template <typename>
static constexpr std::false_type has_foo(...) { return {}; }
};

template <typename Class, typename Sig>
struct has_mem_func_foo :
decltype(has_mem_func_foo_impl<Sig>::template has_foo<Class>(nullptr))
{};

struct bar {
void foo(int) { }
};


int main() {
static_assert( has_mem_func_foo<bar, void(int)>::value, "bar has foo(int)" );
}

我们将 Args... 移动到类本身,然后只将类型传递给函数。这阻止了推导,这使得 nullptr 转换为成员函数指针是可行的,并且事情又开始了。

我还包括一些改进的基于签名的语法,这也意味着它支持返回类型匹配。

请注意,您可能会问错问题。您在询问是否存在具有特定签名的成员函数:通常您想知道是否存在可使用特定参数集调用的成员函数,其返回类型与您的返回值兼容。

namespace details {
template<class T, class Sig, class=void>
struct has_foo:std::false_type{};

template<class T, class R, class... Args>
struct has_foo<T, R(Args...),
typename std::enable_if<
std::is_convertible<
decltype(std::declval<T>().foo(std::declval<Args>()...)),
R
>::value
|| std::is_same<R, void>::value // all return types are compatible with void
// and, due to SFINAE, we can invoke T.foo(Args...) (otherwise previous clause fails)
>::type
>:std::true_type{};
}
template<class T, class Sig>
using has_foo = std::integral_constant<bool, details::has_foo<T, Sig>::value>;

尝试调用T.foo(int),并检查返回值是否兼容。

为了好玩,我将 has_foo 的类型设置为实际上是 true_typefalse_type,而不是继承自。我本来可以:

template<class T, class Sig>
using has_foo = details::has_foo<T, Sig>;

如果我不想要那个额外的功能。

关于c++ - 使用可变参数测试成员函数是否存在,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26363289/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com