//===----------------------------------------------------------------------===// // // Copyright 2024 Bloomberg Finance L.P. // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03 || c++11 || c++14 || c++17 || c++20 // ADDITIONAL_COMPILE_FLAGS: -freflection // ADDITIONAL_COMPILE_FLAGS: -Wno-unneeded-internal-declaration // // // [reflection] #include #include #include constexpr auto ctx = std::meta::access_context::unchecked(); // =============== // basic_functions // =============== namespace basic_functions { // No parameters. consteval int fn0() { return 42; } static_assert([:reflect_invoke(^^fn0, {}):] == 42); static_assert(extract(reflect_invoke(^^fn0, {})) == 42); // Single parameter. consteval int fn1(int i1) { return i1 + 42; } static_assert([:reflect_invoke(^^fn1, {std::meta::reflect_constant(fn0())}):] == 84); static_assert(extract(reflect_invoke(^^fn1, {reflect_invoke(^^fn0, {})})) == 84); // Multiple parameters. consteval int f2(int i1, int i2) { return 42 + i1 + i2; } static_assert([:reflect_invoke(^^f2, {std::meta::reflect_constant(1), std::meta::reflect_constant(2)}):] == 45); static_assert( extract(reflect_invoke(^^f2, {std::meta::reflect_constant(1), std::meta::reflect_constant(2)})) == 45); // 'std::meta::info'-type parameter. using Alias = int; consteval bool isType(std::meta::info R) { return is_type(R); } static_assert([:reflect_invoke(^^isType, {reflect_constant(^^int)}):]); static_assert(![:reflect_invoke(^^isType, {reflect_constant(^^isType)}):]); static_assert(extract(reflect_invoke(^^isType, {reflect_constant(^^Alias)}))); // Static member function. struct Cls { static consteval int fn(int p) { return p * p; } }; static_assert([:reflect_invoke(^^Cls::fn, {std::meta::reflect_constant(4)}):] == 16); // With reflection of constexpr variable as an argument. [[maybe_unused]] static constexpr int five = 5; static_assert([:reflect_invoke(^^fn1, {^^five}):] == 47); } // namespace basic_functions // ================= // default_arguments // ================= namespace default_arguments { consteval int fn(int i1, int i2 = 10) { return 42 + i1 + i2; } // Explicitly providing all arguments. static_assert([:reflect_invoke(^^fn, {std::meta::reflect_constant(1), std::meta::reflect_constant(2)}):] == 45); // Leveraging default argument value for parameter 'i2'. static_assert([:reflect_invoke(^^fn, {std::meta::reflect_constant(5)}):] == 57); } // namespace default_arguments // ================== // lambda_expressions // ================== namespace lambda_expressions { // Ordinary lambda. static_assert( [:reflect_invoke(std::meta::reflect_constant([](int p) { return p * p; }), {std::meta::reflect_constant(3)}):] == 9); // Generic lambda. static_assert( [:reflect_invoke( std::meta::reflect_constant([](T t) requires (sizeof(T) > 1) { return t; }), {std::meta::reflect_constant(4)}):] == 4); } // namespace lambda_expressions // ================== // function_templates // ================== namespace function_templates { template consteval bool sumIsEven(T1 p1, T2 p2) { return (p1 + p2) % 2 == 0; } // Fully specialized function call. static_assert(![:reflect_invoke(^^sumIsEven, {std::meta::reflect_constant(3), std::meta::reflect_constant(4l)}):]); static_assert([:reflect_invoke(^^sumIsEven, {std::meta::reflect_constant(3), std::meta::reflect_constant(7)}):]); // Without specified template arguments. static_assert([:reflect_invoke(^^sumIsEven, {std::meta::reflect_constant(3), std::meta::reflect_constant(4)}):] == false); // With a type parameter pack. template consteval bool sumIsOdd(Ts... ts) { return (... + ts) % 2 == 1; } static_assert([:reflect_invoke(^^sumIsOdd, {std::meta::reflect_constant(2), std::meta::reflect_constant(3l), std::meta::reflect_constant(4ll)}):]); // With a result of 'substitute'. template class C, size_t Sz> consteval bool FirstElemZero(C Container) { return Container[0] == 0; } static_assert( [:reflect_invoke(substitute(^^FirstElemZero, {^^int, ^^std::array, std::meta::reflect_constant(4)}), {std::meta::reflect_constant(std::array{0,2,3,4})}):]); } // namespace function_templates // ====================== // explicit_template_args // ====================== namespace explicit_template_args { template