Home > Enterprise >  iterate over a Variadic Template function and choose pointer arguments
iterate over a Variadic Template function and choose pointer arguments

Time:07-05

I have a Variadic Template function in C and I want to iterate over the template arguments and cherry-pick those arguments that are pointers.

PLEASE SEE THE UPDATE SECTION BELOW.

So, I have the following code below. I wrote a skeleton code that is compilable and runnable.

g   -std=c  17 f3_stackoverflow.cpp && ./a.out

I am just curious about the part that says: LOGIC GOES HERE

#include <iostream>
#include <vector>
#include <utility>

template <typename... Args>
std::vector<std::pair<int, void*>> check(Args... args) {
    std::vector<std::pair<int, void*>> ret;

    // LOGIC GOES HERE

    return ret;
}

void printVector(std::vector<std::pair<int, void*>> v) {
    for(const auto& _v : v) {
        std::cout << _v.first << " : " << _v.second << std::endl;
    }
}

int main(int argc, char const *argv[])
{
    int n = 100;

    int                 a;
    std::vector<int>    b(n);

    float               c;
    std::vector<float>  d(n);

    char                e;
    std::vector<char>   f(n);

    auto pairs = check(a, b.data(), c, d.data(), e, f.data());
    printVector(pairs);
    
    return 0;
}

So, I want to see the following output in the stdout of the program:

1 : 0x123
3 : 0x567
5 : 0x980

UPDATE:

Basically, I am looking for the indexes where the argument is a pointer (e.g., int*, float*, ...) and the address the pointer is pointing to. That is why you see the output that I provided.

Explanation of the output: The second, fourth, and sixth arguments are pointers (hence, 1, 3, 5 in zero-based indexing).

CodePudding user response:

template <int N, typename Arg, typename... Args>
void helper(std::vector<std::pair<int, void*>>& v, Arg arg, Args... args) {
    if constexpr(std::is_pointer_v<Arg>) {
        v.emplace_back(N, (void*)arg);
    }

    if constexpr(sizeof...(args) > 0) {
        helper<N 1,  Args...>(v, args...);
    }
}

template <typename... Args>
std::vector<std::pair<int, void*>> check(Args... args) {
    std::vector<std::pair<int, void*>> ret;
    helper<0>(ret, args...);
    return ret;
}

Demo


Maybe a simpler version using fold expression

template <typename Arg>
void helper(std::vector<std::pair<int, void*>>& v, Arg arg, int idx) {
    if constexpr(std::is_pointer_v<Arg>) {
        v.emplace_back(idx, (void*)arg);
    }
}

template <typename... Args>
std::vector<std::pair<int, void*>> check(Args... args) {
    std::vector<std::pair<int, void*>> ret;
    int n = 0;
    (helper(ret, args, n  ), ...);
    return ret;
}

Demo

CodePudding user response:

There is no need to use recursion. In C 17, you can just combine fold-expression and immediately-invoked lambda to do this

template <typename... Args>
std::vector<std::pair<int, void*>> check(Args... args) {
  std::vector<std::pair<int, void*>> ret;
  int i = 0;
  ([&](auto arg) {
    if constexpr (std::is_pointer_v<decltype(arg)>)
      ret.emplace_back(i, arg);
    i  ;
  }(args), ...);
  return ret;
}

Demo

  • Related