有多种方法可以确定某个函数是否存在,并且有多种方法可以确定某个函数是否具有特定的签名。但有没有办法确定它是否有包含有符号或无符号参数的签名,而名称可能重载?
struct A {
void fn(int) {}
};
struct B {
void fn(unsigned) {}
};
struct C {
void fn(int) {}
void fn(unsigned) {}
};
最接近我认为这是可能的,如果我专门测试每个签名类型,然后如果没有找到,则每个无符号类型。但是,这将在将来排除任何枚举类型或新类型。
答案 0 :(得分:4)
这是一种方法,适用于免费功能和成员功能。标准库中有一个类型特征,用于检查unsigned
- ness std::is_unsigned
阅读下面的答案后,稍微更新我的答案。以下是我将如何检查类型列表是否具有任何无符号数据类型。
我在类型列表中检查条件的常用方法类似于在标准库中执行的方式。我写了一个小特性,可以帮助你概括这一点。请参阅下面的AnyOf
#include <iostream>
#include <type_traits>
using namespace std;
template <template <typename...> class Predicate, typename TypeList>
struct AnyOf {
static constexpr const bool value = false;
};
template <template <typename...> class Predicate,
typename Head, typename... Tail>
struct AnyOf<Predicate, std::tuple<Head, Tail...>> {
static constexpr const bool value
= Predicate<Head>::value
|| AnyOf<Predicate, std::tuple<Tail...>>::value;
};
void foo(int) {}
void bar(unsigned) {}
struct Something {
void foo(int);
void bar(unsigned);
};
namespace detail {
template <typename Func>
struct IsFirstUnsignedImpl;
template <typename ReturnType, typename... Args>
struct IsFirstUnsignedImpl<ReturnType (*) (Args...)> {
constexpr static const bool value
= AnyOf<std::is_unsigned, std::tuple<Args...>>::value;
};
template <typename ClassType, typename ReturnType, typename... Args>
struct IsFirstUnsignedImpl<ReturnType (ClassType::*) (Args...)> {
constexpr static const bool value
= AnyOf<std::is_unsigned, std::tuple<Args...>>::value;
};
} // namespace detail
template <typename Func>
struct IsFirstUnsigned {
constexpr static bool value
= detail::IsFirstUnsignedImpl<std::decay_t<Func>>::value;
};
int main() {
cout << std::boolalpha << IsFirstUnsigned<decltype(foo)>::value << endl;
cout << std::boolalpha << IsFirstUnsigned<decltype(bar)>::value << endl;
cout << std::boolalpha << IsFirstUnsigned<decltype(&Something::foo)>::value
<< endl;
cout << std::boolalpha << IsFirstUnsigned<decltype(&Something::bar)>::value
<< endl;
return 0;
}
答案 1 :(得分:1)
是。我有一个解决方案,但它没有处理函数使用不同的无符号类型重载的情况。
template<typename T>
struct has_fn {
private:
struct to_unsigned {
template<typename U, std::enable_if_t<std::is_unsigned<U>::value>* = nullptr>
operator U () const;
};
template<typename U, void_t<decltype(std::declval<U>().fn(to_unsigned{}))>* = nullptr>
static std::true_type test(int);
template<typename>
static std::false_type test(...);
public:
constexpr static bool value = decltype(test<T>(0))::value;
};
你可以这样使用它:
int main() {
struct A {
void fn(int) {}
};
struct B {
void fn(unsigned) {}
};
struct C {
void fn(int) {}
void fn(unsigned) {}
};
static_assert(!has_fn<A>::value, "");
static_assert(has_fn<B>::value, "");
static_assert(has_fn<C>::value, "");
}
如果你没有C ++ 17,你可以像这样实现void_t
:
template<typename...>
using void_t = void;
答案 2 :(得分:1)
此解决方案检查参数列表中是否存在任何无符号类型。这不会(也不能)适用于重载函数,因为重载决策取决于调用者。这里我们只是检查函数本身。
#include <iostream>
#include <type_traits>
template < typename >
struct has_unsigned_param : std::false_type {};
template < typename R, typename T >
struct has_unsigned_param < R(T) >
{
static constexpr bool value = std::is_unsigned < T >::value;
};
template < typename R, typename T, typename ... S >
struct has_unsigned_param < R(T,S...) >
{
static constexpr bool value =
std::is_unsigned < T >::value || has_unsigned_param < R(S...) >::value;
};
template < typename C, typename R, typename ... T >
struct has_unsigned_param < R(C::*)(T...) >
{
static constexpr bool value = has_unsigned_param < R(T...) >::value;
};
struct foo {
void test1(int) {}
void test2(unsigned int) {}
void test3(int, unsigned int) {}
void test4(int, unsigned int, double) {}
void test5(int, unsigned int, float, unsigned char) {}
void test6(int, int, float, char) {}
};
void test1(int) {}
void test2(unsigned int) {}
void test3(int, unsigned int) {}
void test4(int, unsigned int, double) {}
void test5(int, unsigned int, float, unsigned char) {}
void test6(int, int, float, char) {}
int main()
{
std::cout << std::boolalpha;
std::cout << has_unsigned_param < decltype(test1) >::value << '\n';
std::cout << has_unsigned_param < decltype(test2) >::value << '\n';
std::cout << has_unsigned_param < decltype(test3) >::value << '\n';
std::cout << has_unsigned_param < decltype(test4) >::value << '\n';
std::cout << has_unsigned_param < decltype(test5) >::value << '\n';
std::cout << has_unsigned_param < decltype(test6) >::value << '\n';
std::cout << has_unsigned_param < decltype(&foo::test1) >::value << '\n';
std::cout << has_unsigned_param < decltype(&foo::test2) >::value << '\n';
std::cout << has_unsigned_param < decltype(&foo::test3) >::value << '\n';
std::cout << has_unsigned_param < decltype(&foo::test4) >::value << '\n';
std::cout << has_unsigned_param < decltype(&foo::test5) >::value << '\n';
std::cout << has_unsigned_param < decltype(&foo::test6) >::value << '\n';
}