text: // Copyright (c) Microsoft Corporation.
  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  
  // test <functional>, part 6
  #define TEST_NAME "<functional>, part 6"
  
  #define _HAS_DEPRECATED_ADAPTOR_TYPEDEFS 1
  #define _SILENCE_CXX17_ADAPTOR_TYPEDEFS_DEPRECATION_WARNING
  
  #include "tdefs.h"
  #include "tfuns.h"
  #include <functional>
  #include <iostream>
  
  #define PH1  STD placeholders::_1
  #define PH2  STD placeholders::_2
  #define PH3  STD placeholders::_3
  #define PH4  STD placeholders::_4
  #define PH5  STD placeholders::_5
  #define PH6  STD placeholders::_6
  #define PH7  STD placeholders::_7
  #define PH8  STD placeholders::_8
  #define PH9  STD placeholders::_9
  #define PH10 STD placeholders::_10
  
  static void t_bad() { // test bad_function_call
  #if NO_EXCEPTIONS
  #else // NO_EXCEPTIONS
      typedef double(Fd)(double);
      typedef STD function<Fd> Myfunc;
      bool ok = false;
  
      try { // test exception for empty function object
          Myfunc fd1;
          std::cout << fd1(3) << std::endl;
      } catch (const STD bad_function_call&) { // handle bad call
          ok = true;
      }
      CHECK_MSG("empty function throws bad_function_call", ok);
  #endif // NO_EXCEPTIONS
  }
  
  static void t_bind() { // test STD bind
      bool ans;
      typedef decltype(STD bind(&f0)) bind0;
      CHECK(STD is_bind_expression<bind0>::value);
      ans = STD is_convertible<STD is_bind_expression<bind0>, STD true_type>::value;
      CHECK(ans);
  
      typedef decltype(PH3) ph3;
      CHECK_INT(STD is_placeholder<ph3>::value, 3);
      ans = STD is_convertible<STD is_placeholder<ph3>, STD integral_constant<int, 3>>::value;
      CHECK(ans);
  
      CHECK(!STD is_bind_expression<int>::value);
      ans = STD is_convertible<STD is_bind_expression<int>, STD false_type>::value;
      CHECK(ans);
  
      CHECK_INT(STD is_placeholder<int>::value, 0);
      ans = STD is_convertible<STD is_placeholder<int>, STD integral_constant<int, 0>>::value;
      CHECK(ans);
  
      // POINTER TO FUNCTION
      CALL0(STD bind(&f0));
      CALL1(STD bind(&f1, PH1));
      CALL2(STD bind(&f2, PH1, PH2));
      CALL3(STD bind(&f3, PH1, PH2, PH3));
      CALL4(STD bind(&f4, PH1, PH2, PH3, PH4));
      CALL5(STD bind(&f5, PH1, PH2, PH3, PH4, PH5));
      CALL6(STD bind(&f6, PH1, PH2, PH3, PH4, PH5, PH6));
      CALL7(STD bind(&f7, PH1, PH2, PH3, PH4, PH5, PH6, PH7));
      CALL8(STD bind(&f8, PH1, PH2, PH3, PH4, PH5, PH6, PH7, PH8));
      CALL9(STD bind(&f9, PH1, PH2, PH3, PH4, PH5, PH6, PH7, PH8, PH9));
      CALL10(STD bind(&f10, PH1, PH2, PH3, PH4, PH5, PH6, PH7, PH8, PH9, PH10));
  
      match_result_type<int>(STD bind(&f0));
      match_result_type<int>(STD bind(&f1, PH1));
      match_result_type<int>(STD bind(&f2, PH1, PH2));
      match_result_type<int>(STD bind(&f3, PH1, PH2, PH3));
      match_result_type<int>(STD bind(&f4, PH1, PH2, PH3, PH4));
      match_result_type<int>(STD bind(&f5, PH1, PH2, PH3, PH4, PH5));
      match_result_type<int>(STD bind(&f6, PH1, PH2, PH3, PH4, PH5, PH6));
      match_result_type<int>(STD bind(&f7, PH1, PH2, PH3, PH4, PH5, PH6, PH7));
      match_result_type<int>(STD bind(&f8, PH1, PH2, PH3, PH4, PH5, PH6, PH7, PH8));
      match_result_type<int>(STD bind(&f9, PH1, PH2, PH3, PH4, PH5, PH6, PH7, PH8, PH9));
      match_result_type<int>(STD bind(&f10, PH1, PH2, PH3, PH4, PH5, PH6, PH7, PH8, PH9, PH10));
  
      // FUNCTION OBJECT
      funobj fo;
      CALL0(STD bind(fo));
      CALL1(STD bind(fo, PH1));
      CALL2(STD bind(fo, PH1, PH2));
      CALL3(STD bind(fo, PH1, PH2, PH3));
      CALL4(STD bind(fo, PH1, PH2, PH3, PH4));
      CALL5(STD bind(fo, PH1, PH2, PH3, PH4, PH5));
      CALL6(STD bind(fo, PH1, PH2, PH3, PH4, PH5, PH6));
      CALL7(STD bind(fo, PH1, PH2, PH3, PH4, PH5, PH6, PH7));
      CALL8(STD bind(fo, PH1, PH2, PH3, PH4, PH5, PH6, PH7, PH8));
      CALL9(STD bind(fo, PH1, PH2, PH3, PH4, PH5, PH6, PH7, PH8, PH9));
      CALL10(STD bind(fo, PH1, PH2, PH3, PH4, PH5, PH6, PH7, PH8, PH9, PH10));
  
      match_result_type<int>(STD bind(fo));
      match_result_type<int>(STD bind(fo, PH1));
      match_result_type<int>(STD bind(fo, PH1, PH2));
      match_result_type<int>(STD bind(fo, PH1, PH2, PH3));
      match_result_type<int>(STD bind(fo, PH1, PH2, PH3, PH4));
      match_result_type<int>(STD bind(fo, PH1, PH2, PH3, PH4, PH5));
      match_result_type<int>(STD bind(fo, PH1, PH2, PH3, PH4, PH5, PH6));
      match_result_type<int>(STD bind(fo, PH1, PH2, PH3, PH4, PH5, PH6, PH7));
      match_result_type<int>(STD bind(fo, PH1, PH2, PH3, PH4, PH5, PH6, PH7, PH8));
      match_result_type<int>(STD bind(fo, PH1, PH2, PH3, PH4, PH5, PH6, PH7, PH8, PH9));
      match_result_type<int>(STD bind(fo, PH1, PH2, PH3, PH4, PH5, PH6, PH7, PH8, PH9, PH10));
  }
  
  struct funobj_no_nested { // callable type with no nested result_type
      template <class Fty>
      struct result { // make non-decltype version of result_of happy
          typedef int type;
      };
      int operator()();
      template <class T1>
      int operator()(T1);
      template <class T1, class T2>
      int operator()(T1, T2);
      template <class T1, class T2, class T3>
      int operator()(T1, T2, T3);
      template <class T1, class T2, class T3, class T4>
      int operator()(T1, T2, T3, T4);
  };
  
  static void t_bind_no_nested() {
      funobj_no_nested fn;
      CHECK_INT(has_result_type(STD bind(fn)), false);
      CHECK_INT(has_result_type(STD bind(fn, PH1)), false);
      CHECK_INT(has_result_type(STD bind(fn, PH1, PH2)), false);
      CHECK_INT(has_result_type(STD bind(fn, PH1, PH2, PH3)), false);
      CHECK_INT(has_result_type(STD bind(fn, PH1, PH2, PH3, PH4)), false);
  }
  
  void test_main() { // test header <functional>
      t_bad();
      t_bind();
      t_bind_no_nested();
  }
  