是否有可能确定函数的参数是否有符号或无符号的可能重载函数?

时间:2017-06-01 04:41:37

标签: c++ c++11 c++14

有多种方法可以确定某个函数是否存在,并且有多种方法可以确定某个函数是否具有特定的签名。但有没有办法确定它是否有包含有符号或无符号参数的签名,而名称可能重载

实施例

struct A {
 void fn(int) {}
};

struct B {
 void fn(unsigned) {}
};

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

最接近我认为这是可能的,如果我专门测试每个签名类型,然后如果没有找到,则每个无符号类型。但是,这将在将来排除任何枚举类型或新类型。

3 个答案:

答案 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, "");
}

Live example

如果你没有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';
}

Live example