Example
int main() {
struct arg { arg(int n) { std::printf("arg%d ", n); } };
auto il = {arg{1}, arg{2}, arg{3}}; // arg1 arg2 arg3
[](auto...){}(arg{1}, arg{2}, arg{3}); // order unspecified
}
Puzzle
- Can you implement a subroutine
is_evaluating_args_from_left_to_right
which returns { true: if expression arguments are evaluated from left to right, false: otherwise }?
/*TODO - is_evaluating_args_from_left_to_right */
int main() {
using namespace boost::ut;
"function arguments evaluation order"_test = [] {
#if defined(__clang__)
expect(is_evaluating_args_from_left_to_right()) << "run-time";
expect(constant<is_evaluating_args_from_left_to_right()>) << "compile-time";
#else
expect(not is_evaluating_args_from_left_to_right()) << "run-time";
expect(constant<is_evaluating_args_from_left_to_right()>) << "compile-time";
#endif
};
}
Solutions
constexpr bool is_evaluating_args_from_left_to_right() {
std::array<int, 3> ex = {1,2,3};
int i=0;
std::array<int, 3> tst;
auto f = [&i, &tst] (auto e) { return tst[i++]=e;};
[](auto...){}(f(1),f(2),f(3));
return std::equal(ex.begin(), ex.end(), tst.begin());
}
constexpr auto is_evaluating_args_from_left_to_right() {
auto i = 0;
struct S {
constexpr S(int& i) : first(i++ == 0) {}
bool first;
};
return [](auto x, auto) { return x.first; }(S{i}, S{i});
}
constexpr auto is_evaluating_args_from_left_to_right() {
auto i = 0;
auto f = [&]() { return i++; };
return [](auto lhs, auto rhs) { return lhs < rhs; }(f(), f());
}
constexpr auto is_evaluating_args_from_left_to_right = [] {
auto result = false;
[](auto...) { } (result = true, result = false);
return not result;
};