Info
-
Did you know that different overloads can have different specifiers?
Example
constexpr auto foo(auto) { return 42; }
consteval auto foo(auto f) requires requires { f.value; } { return f.value; }
int main(int argc, char**) {
std::cout << foo(argc); // prints 42
constexpr struct {
int value{88};
} v;
std::cout << foo(v); // prints 88
}
Puzzle
- Can you implement a function f which for { 0 args: is run-time - returns 42; 1 arg: is run/compile-time, returns arg; >1 args: is compile-time, returns sum of args... }
auto f(...); // TODO
template<auto> auto is_compile_time() {}
int main() {
using namespace boost::ut;
"run-time call"_test = [] {
expect(42_i == f());
expect(not [](auto... ts) { return requires { is_compile_time<f(ts...)>(); }; }());
};
"constexpr call"_test = [] {
"compile-time call"_test = [] {
expect(constant<42_i == f(42)>);
expect(requires { is_compile_time<f(42)>(); });
constexpr auto i = 43;
expect(constant<43_i == f(43)>);
};
"run-time call"_test = [] {
auto i = 44;
expect(44_i == f(i));
};
};
"consteval call"_test = [] {
expect(constant<3_i == f(1, 2)>);
expect(constant<6_i == f(1, 2, 3)>);
auto i = 1;
//f(42, i); // should not compile
};
}
Solutions
auto f() { return 42; }
constexpr auto f(auto v) { return v; }
template<typename ... Args> consteval auto f(Args... args) { return (0 + ... + args); }
auto f() { return 42; }
constexpr auto f(auto arg) { return arg; }
consteval auto f(auto... args) { return (... + args); }
auto f() { return 42; }
constexpr auto f(auto value) { return value; }
consteval auto f(auto... values) requires (sizeof...(values) > 1) { return (... + values); }