1

I want to apply certain functionality to some elements of a tuple based on a given condition or constraint of the types.

Below is a small dummy example where I want to call a callback function for all the elements in the tuple that holds an arithmetic type. In my current solution, I use std::apply and if constexpr on the type constraint as the condition to call the callback.

However, I assume this is iterating through all the elements of the tuple?

And now I am wondering if there is an alternative to do this. In my head, it should be possible to select the indices of the elements of interest at compile-time, because all the types are known and then apply the functionality only for the elements at those indices. But I don't know if this is possible, nor how to translate this to code.

#include <iostream>
#include <string>
#include <tuple>
#include <type_traits>

template <typename... Args>
struct Foo {
    using my_tuple = std::tuple<Args...>;

    template <typename Fn>
    void CallForArithmetic(Fn&& fn) {
        auto arithmetic_call = [&]<typename T>(const T& x) {
            if constexpr (std::is_arithmetic_v<T>) {
                fn(x);
            }
        };

        std::apply([&](auto&&... arg) { (arithmetic_call(arg), ...); }, tuple_);
    };

   private:
    my_tuple tuple_;
};

int main() {
    Foo<int, std::string> foo{};
    int calls = 0;
    // will be called only once for int type
    foo.CallForArithmetic(
        [&calls](const auto& arg) { std::cout << calls++ << '\n'; }); 
}
mennok
  • 35
  • 4
  • 3
    You current way seems the simplest, and we might expect from compiler to avoid the no-op call completly... – Jarod42 Jun 16 '22 at 18:19

1 Answers1

1

It's really "as if" you are iterating over the full tuple. In general, the compiled program will only do that if it has to, or if all optimisations are disabled, to aid debugging. And indeed, starting from -O1 (gcc) or -O2 (clang), a slightly simplified version of your code compiles to "return 1;":

main:
        mov     eax, 1
        ret

Note: msvc finds the same result, but generates a lot of extra clutter.

So, as Jarod42 suggested, you can definitely expect your compiler to figure this out, and go with the solution that is easiest for you as a human. And if you're not sure, Compiler Explorer is a great tool for questions like yours.

sigma
  • 2,758
  • 1
  • 14
  • 18