aboutsummaryrefslogtreecommitdiff
path: root/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/bind_return_type.pass.cpp
blob: 63d3c9b0de9235fb45fe0578a7f914ebd4e12dff (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++98, c++03

// <functional>

// template<CopyConstructible Fn, CopyConstructible... Types>
//   unspecified bind(Fn, Types...);
// template<Returnable R, CopyConstructible Fn, CopyConstructible... Types>
//   unspecified bind(Fn, Types...);

// Check that the call operators have the proper return type and that they
// only SFINAE away when too few arguments are provided. Otherwise they should
// be well formed and should ignore any additional arguments.

#include <functional>
#include <type_traits>
#include <cassert>

int dummy = 42;

int return_value(int) { return dummy; }
int& return_lvalue(int) { return dummy; }
const int& return_const_lvalue(int) { return dummy; }
int&& return_rvalue(int) { return std::move(dummy); }
const int&& return_const_rvalue(int) { return std::move(dummy); }

template <class Bind, class ...Args>
auto CheckCallImp(int)
    -> decltype((std::declval<Bind>()(std::declval<Args>()...)), std::true_type{});

template <class Bind, class ...>
auto CheckCallImp(long) -> std::false_type;

template <class ...Args>
constexpr bool CheckCall() {
    return decltype(CheckCallImp<Args...>(0))::value;
}

template <class Expect, class Fn>
void do_test(Fn* func) {
    using namespace std::placeholders;
    auto ret = std::bind(func, _1);
    auto ret_r = std::bind<Expect>(func, _1);
    using Bind = decltype(ret);
    using BindR = decltype(ret_r);

    using Ret = decltype(ret(42));
    using Ret2 = decltype(ret(42, 43)); // Test that the extra argument is discarded.
    using RetR = decltype(ret_r(42));
    using RetR2 = decltype(ret_r(42, 43));

    static_assert(std::is_same<Ret, Expect>::value, "");
    static_assert(std::is_same<Ret2, Expect>::value, "");
    static_assert(std::is_same<RetR, Expect>::value, "");
    static_assert(std::is_same<RetR2, Expect>::value, "");

    Expect exp = ret(100); // the input value is ignored. dummy is returned.
    Expect exp2 = ret(101, 102);
    Expect exp_r = ret_r(100);
    Expect exp_r2 = ret_r(101, 102);

    assert(exp == 42);
    assert(exp2 == 42);
    assert(exp_r == 42);
    assert(exp_r2 == 42);

    if ((std::is_reference<Expect>::value)) {
        assert(&exp == &dummy);
        assert(&exp2 == &dummy);
        assert(&exp_r == &dummy);
        assert(&exp_r2 == &dummy);
    }
    // Check that the call operator SFINAE's away when too few arguments
    // are provided but is well-formed otherwise.
    {
        static_assert(!CheckCall<Bind>(), "");
        static_assert(CheckCall<Bind, int>(), "");
        static_assert(CheckCall<Bind, int, int>(), "");
        static_assert(!CheckCall<BindR>(), "");
        static_assert(CheckCall<BindR, int>(), "");
        static_assert(CheckCall<BindR, int, int>(), "");
    }
}


// Test but with an explicit return type which differs from the real one.
template <class Expect, class Fn>
void do_test_r(Fn* func) {
    using namespace std::placeholders;
    auto ret = std::bind<Expect>(func, _1);
    using Bind = decltype(ret);
    using Ret = decltype(ret(42));
    using Ret2 = decltype(ret(42, 43)); // Test that the extra argument is discarded.
    static_assert(std::is_same<Ret, Expect>::value, "");
    static_assert(std::is_same<Ret2, Expect>::value, "");
    Expect exp = ret(100); // the input value is ignored
    Expect exp2 = ret(101, 102);
    assert(exp == 42);
    assert(exp2 == 42);
    // Check that the call operator SFINAE's away when too few arguments
    // are provided but is well-formed otherwise.
    {
        static_assert(!CheckCall<Bind>(), "");
        static_assert(CheckCall<Bind, int>(), "");
        static_assert(CheckCall<Bind, int, int>(), "");
    }
}

int main()
{
    do_test<int>(return_value);
    do_test<int&>(return_lvalue);
    do_test<const int&>(return_const_lvalue);
    do_test<int&&>(return_rvalue);
    do_test<const int&&>(return_const_rvalue);

    do_test_r<long>(return_value);
    do_test_r<long>(return_lvalue);
    do_test_r<long>(return_const_lvalue);
    do_test_r<long>(return_rvalue);
    do_test_r<long>(return_const_rvalue);

}