2017-06-01 10 views
2

関数が存在するかどうかを判断する方法や、関数に特定の署名があるかどうかを判断する方法があります。しかし、名前にがオーバーロードされている間に、署名付きまたは署名なしのパラメータを含むシグネチャがあるかどうかを判断する方法はありますか?関数のパラメータがオーバーロードされている可能性があるかどうかを判断することは可能ですか?

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

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

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

私はすべての署名タイプ、および見つからない場合は、すべてのunsigned型のために特別にテストされている場合、私はこれが可能になると考えることが一番近いです。ただし、今後は列挙型や新しい型を除外します。

+0

あなたはもし 'のstd :: numeric_limitsの ::分()'、ゼロに等しい、すなわち 'もし(!のstd :: numeric_limitsの ::分())をテストすることができ{/ *は符号なし* /} 'です。 – Bernard

+0

@Bernard:ちょうど 'T 'を得るためにどのように提案しますか? – MSalters

+0

@MSalters申し訳ありませんが、私は質問を誤解しました。 – Bernard

答えて

4

これを行う1つの方法は、自由な関数とメンバ関数の両方で動作します。以下の答え、私の答えにわずかな更新を読んだ後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; 
} 
+0

私はまた、戻り値の型をテンプレートします。さもなければ、何も返さない関数(つまり 'void')に限定されます。 –

+0

@HenriMenke done – Curious

+0

@Curiousメンバ関数へのポインタをこのようにすると、可能なすべての修飾子の組み合わせにオーバーロードを追加する必要があることに注意してください(それは[https:// github.com/gracicot/kangaru/blob/master/include/kangaru/detail/function_traits。hp#L36) –

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; 
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

+0

答えは「いいえ」ですか?それも私の理解だった。私はちょうど確信したかった。これには答えが含まれていますが、他の多くのものも含まれています。 – Adrian

関連する問題