1//===----------------------------------------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10// <functional>
11
12// template<Returnable R, CopyConstructible... ArgTypes>
13// class function<R(ArgTypes...)> {
14// public:
15//   typedef R result_type;
16//   typedef T1 argument_type;          // iff sizeof...(ArgTypes) == 1 and
17//                                      // the type in ArgTypes is T1
18//   typedef T1 first_argument_type;    // iff sizeof...(ArgTypes) == 2 and
19//                                      // ArgTypes contains T1 and T2
20//   typedef T2 second_argument_type;   // iff sizeof...(ArgTypes) == 2 and
21//                                      // ArgTypes contains T1 and T2
22//  ...
23//  };
24
25#include <functional>
26#include <type_traits>
27
28
29template <typename T>
30class has_argument_type
31{
32    typedef char yes;
33    typedef long no;
34
35    template <typename C> static yes check( typename C::argument_type * );
36    template <typename C> static no  check(...);
37public:
38    enum { value = sizeof(check<T>(0)) == sizeof(yes) };
39};
40
41template <typename T>
42class has_first_argument_type
43{
44    typedef char yes;
45    typedef long no;
46
47    template <typename C> static yes check( typename C::first_argument_type * );
48    template <typename C> static no  check(...);
49public:
50    enum { value = sizeof(check<T>(0)) == sizeof(yes) };
51};
52
53
54template <typename T>
55class has_second_argument_type
56{
57    typedef char yes;
58    typedef long no;
59
60    template <typename C> static yes check( typename C::second_argument_type *);
61    template <typename C> static no  check(...);
62public:
63    enum { value = sizeof(check<T>(0)) == sizeof(yes) };
64};
65
66template <class F, class return_type>
67void test_nullary_function ()
68{
69    static_assert((std::is_same<typename F::result_type, return_type>::value), "" );
70    static_assert((!has_argument_type<F>::value), "" );
71    static_assert((!has_first_argument_type<F>::value), "" );
72    static_assert((!has_second_argument_type<F>::value), "" );
73}
74
75template <class F, class return_type, class arg_type>
76void test_unary_function ()
77{
78    static_assert((std::is_same<typename F::result_type, return_type>::value), "" );
79    static_assert((std::is_same<typename F::argument_type,  arg_type>::value), "" );
80    static_assert((!has_first_argument_type<F>::value), "" );
81    static_assert((!has_second_argument_type<F>::value), "" );
82}
83
84template <class F, class return_type, class arg_type1, class arg_type2>
85void test_binary_function ()
86{
87    static_assert((std::is_same<typename F::result_type,        return_type>::value), "" );
88    static_assert((std::is_same<typename F::first_argument_type,  arg_type1>::value), "" );
89    static_assert((std::is_same<typename F::second_argument_type, arg_type2>::value), "" );
90    static_assert((!has_argument_type<F>::value), "" );
91}
92
93template <class F, class return_type>
94void test_other_function ()
95{
96    static_assert((std::is_same<typename F::result_type, return_type>::value), "" );
97    static_assert((!has_argument_type<F>::value), "" );
98    static_assert((!has_first_argument_type<F>::value), "" );
99    static_assert((!has_second_argument_type<F>::value), "" );
100}
101
102int main()
103{
104    test_nullary_function<std::function<int()>, int>();
105    test_unary_function  <std::function<double(int)>, double, int>();
106    test_binary_function <std::function<double(int, char)>, double, int, char>();
107    test_other_function  <std::function<double(int, char, double)>, double>();
108}
109