是否可以确定函数的参数是否已签名或无符号,以实现可能性超载函数



有一些方法可以确定是否存在函数,并且有一些方法可以确定函数是否具有特定的签名。但是,有没有办法确定它是否具有包含签名或未签名参数的签名,而该名称可以超载

示例

struct A {
 void fn(int) {}
};
struct B {
 void fn(unsigned) {}
};
struct C {
 void fn(int) {}
 void fn(unsigned) {}
};

我认为最接近的是,如果我专门针对每种签名类型进行了专门测试,然后如果找不到的话,每种未签名类型。但是,将来将排除任何枚举类型或新类型。

这是一种做到这一点的方法,可用于自由功能以及成员功能。标准库中有一个类型特征,可以检查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;
}

是。我有一个解决方案,但它无法处理该功能与不同的无签名类型重载的情况。

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;

此解决方案检查参数列表中是否有任何任何 unsigned类型。这不能(也不能(用于超载功能,因为超载分辨率取决于呼叫者。在这里,我们只检查功能本身。

#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';
}

实时示例

最新更新