简体   繁体   中英

Storing arguments in a variadic template function without using boost::any

I have written the following short code in C++11 of a variable template function and store the arguments into a vector of type boost::any. It is working perfectly, but I don't want to use the boost::any library (due to some limitation).

#include <boost/any.hpp>

template <class Var, class... Args>
void cpp_for(Var *variable, uint32_t numParams, Args... args)
{
    std::vector<boost::any> arguments{args...};

    if(arguments.size() != numParams)
        throw std::runtime_error("mismatch");

    for(uint32_t i = 0; i < numParams; ++i)
        variable[i] = *(boost::unsafe_any_cast<Var>(&arguments[i]));
}

And I call the function like this:

cpp_for(myObj->var, 3, 0x56, 0x23, 0x10);

Or

cpp_for(myObj2->var, 2, myObj2->var2, myObj2->var3);

Is there any way to store the arguments and process them one by one without the need for boost::any?

Edit 1: my arguments are all of the same type.

Edit 2: Since the goal of the code above is assignment , then creating an extra data structure (vector) is useless. Check 'Nir Friedman''s answer for a more efficient solution.

You could use std::common_type , eg:

template <class Var, class... Args>
void CPP_FOR(Var *variable, uint32_t numParams, Args... args)
{
    std::vector<std::common_type_t<Args...>> arguments{args...};
    // do stuff with arguments
}

You can also remove numParams and the runtime check because this will fail at compile time if there is no common type. And if you only want to iterate over the arguments, a vector is maybe overkill... so something like:

template <class Var, class... Args>
void CPP_FOR(Var *variable, Args... args)
{
    std::common_type_t<Args...> arguments[]{args...};
    for(size_t i = 0; i < sizeof...(Args); ++i)
        variable[i] = /* ... */;
}

Note that both of these will fails if sizeof... (Args) is 0, ie you are calling with only a Var* - You may want to handle this case separately if necessary.

Assuming that your goal is really just to perform assignments, you don't need a vector at all.

template <class Var, class... Args>
void CPP_FOR(Var *variable, uint32_t numParams, Args... args)
{    
    if(sizeof...(Args) != numParams)
        throw std::runtime_error("mismatch");

    int i = 0;
    int temp [] = {(variable[i++] = args, 0)...};
}

Live example: http://coliru.stacked-crooked.com/a/710a09332bf2c965

Not only is this zero overhead compared to creating a vector that is hard to optimize away, but it will allow implicit conversions in the most natural way. Other approaches may have surprises.

If you know that there's going to be at least one argument, you can write your function slightly differently to do so.

template <typename Arg, typename... Args>
void cpp_for(Arg arg, Args... args) {
  std::vector<Arg> vec { arg, args... };
  // ...
}

However, this will fail if the argument list is empty. The easiest solution to this is simply to add a second overload of cpp_for which takes no arguments.

void cpp_for() {
  std::vector<SomeDefaultType> vec; // Empty vector
  // ...
}

Of course, you only need to do so if it makes sense to call your function with zero arguments.

Bear in mind that this approach will give positively miserable error messages if Args and Arg don't all end up being the same type. This can be remedied with some careful use of static_assert .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM