2

How to convert variadic function arguments to array? I need something like this:

template <typename T>
struct Colordata
{
public:
    T dataFirst;
    T dataLast;

    template <typename... Ta>
    Colordata(Ta... args)
    {
        constexpr std::size_t n = sizeof...(Ta);
        std::cout << n << std::endl;
        dataFirst = (args..)[0];
        dataLast = (args...)[n - 1];
        return;
    }   
};

int main(int argc, char const *argv[])
{
    auto a = Colordata<float>(1.0f, 2.2f, 3.3f, 4.3f, 5.5f);
    return 0;
}

I tried to use variadic arguments as T args, ... and use functions from stdarg.h but then I can't get the count of arguments.

4
  • Variadic packs cannot be indexed like an array. You can, however, extract specific elements, though it requires a bit of template work since you need to expand the variadic pack and retrieve the Nth entry Commented Sep 8, 2021 at 17:15
  • 3
    From the way your class is written, it seems you only want to get the first and last elements of the variadic pack. If so, edit your question to say that precisely. Getting the arguments into an array is an XY problem in this case. Commented Sep 8, 2021 at 17:17
  • Also note that a pack can have different types for each argument. When you do Colordata<float> you are just specifying the type of the first argument. The rest are deduced by the compiler. In this case they are all floats though. Commented Sep 8, 2021 at 17:19
  • 1
    I think that what the OP really needs is std::initializer_list<float>, and not a variadic array... But since it's unclear what they're doing, it's hard to give good advice. Commented Sep 8, 2021 at 17:30

2 Answers 2

3

You can't convert a parameter pack into an array. You could create an array from one, but that would copy, and that would be wasteful. Instead, we can "convert" the parameter pack into a tuple of references, and then use get to index into that tuple. That would look like

template <typename... Ta>
Colordata(Ta... args)
{
    constexpr std::size_t n = sizeof...(Ta);
    static_assert(n >= 1, "must pass at least one argument");
    std::cout << n << std::endl;
    auto& tuple = std::tie(args...);
    dataFirst = std::get<0>(tuple)
    dataLast = std::get<n - 1>(tuple);
}  
Sign up to request clarification or add additional context in comments.

5 Comments

I think that what the OP really needs is std::initializer_list<float>, and not a variadic array... But since it's unclear what they're doing, it's hard to give good advice.
@MooingDuck That it is. I'm assuming something more complicated is going on, because taking any amount of parameters but only using 2 doesn't make a lot of sense.
@MooingDuck Ok. I just wanted to see an example of how to works with variadic arguments. In c++ I use these arguments for the first time. In the previous language which I used variadic arguments are dynamic arrays and this one requires bigger memory than a static array. I wanna create a new &T[n] array. using arguments. What is the best way to do that?
Thank you. How can I use std::get with variables? I tried:` std::get<i>(tuple);` where i is the index on for loop
@WusikiJeronii Since get uses a template parameter, the value you pass to it must be a compile time constant, which i is not. If you are trying to do something different from what you have asked here, you should ask a new question.
2

From what is being done with the arguments to the constructor, there doesn't seem to be any need for an array, or to store the arguments in any fashion. If you just need the first and last arguments, you can write functions that do these things separately.

Getting the first argument is trivial

template <typename First, typename... Ts>
auto first_arg(First const & first, Ts const & ...)
{
  return first;
} 

Getting the last argument is only slightly more involved, but can be done with a base case overload

template <typename Last>
auto last_arg(Last const & last)
{
  return last;
} 

template <typename First, typename... Ts>
auto last_arg(First const &, Ts const & ... ts)
{
  return last_arg(ts...);
} 

You can now reuse these functions in other places that you need, and in the constructor you've written, you can do

template <typename... Tas>
Colordata(Ts... args)
{
  dataFirst = first_arg(args...);
  dataLast = last_arg(args...);
}

2 Comments

Can't one use template <typename FirstT, typename LastT, typename... Tas> Colordata(FirstT first, Ts... args, LastT last) {? I'd have to test to find out
@MooingDuck No, the variadic arguments must be trailing in the function signature.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.