Specifying One Type For All Arguments Passed to Variadic Function or Variadic Template Function W/Out Using Array, Vector, Structs, etc

Specifying one type for all arguments passed to variadic function or variadic template function w/out using array, vector, structs, etc?

You can just accept the arguments by the variadic template and let typechecking check the validity later on when they are converted.

You can check convertibility on the function interface level though, to make use of overload resolution for rejecting outright wrong arguments for example, by using SFINAE

template<typename R, typename...> struct fst { typedef R type; };

template<typename ...Args>
typename fst<void,
typename enable_if<
is_convertible<Args, ToType>::value
>::type...
>::type
f(Args...);

For your use-case if you know the steps to go from an std::array<> to your dragon_list_t then you have already solved it though according to the first option above ("convert-later"):

template<typename ...Items>
dragon_list_t make_dragon_list(Items... maidens) {
std::array<Maiden, sizeof...(Items)> arr = {{ maidens ... }};
// here be dragons
}

If you combine this with the above is_convertible approach you have a reject-early template that also does overload resolution on arguments and rejects them if not applicable.

How to get the element type of each container passed to variadic template function

You'd have to do something like:

template<typename ...T>
void foo(T...args) {
auto f = [](auto x){
using U = typename decltype(x)::value_type;
int size = sizeof(U);
int var = sizeof(U);
};
(f(args),...);;
}

If later on you'd like to change the lambda to accept references, such as f = [](auto&& x), you'd have to use std::decay_t, since the decltype(x) will give you a reference type, and a reference type does not have any nested type members:

template<typename ...T>
void foo(T...args) {
auto f = [](auto&& x){
using U = typename std::decay_t<decltype(x)>::value_type;
int size = sizeof(U);
int var = sizeof(U);
};
(f(args),...);;
}

Example: https://godbolt.org/z/fPr4Gh

How to set the same type for all arguments in this example?

The funny thing is that your current code already ensures that calls like

add(&vI, 10, 10.f, 20); 

doesn't compile. If an argument's type is different from the vector's value type, then eventually it will become the second argument in a call like

add(&vI, 10.f, 20);

and then template argument deduction will fail because it deduces conflicting types for T.

If you want to reduce the horrendous amount of error messages when the deduction failure happens deep in the recursion, SFINAE or static_assert can help. I personally prefer Columbo's trick:

template<bool...> class bool_pack;
template<bool...b>
using all_true = std::is_same<bool_pack<true, b...>, bool_pack<b..., true>>;

template <class T, class... T2>
void add(vector<T> *v, T n, T2... rest)
{
static_assert(all_true<std::is_same<T, T2>{}...>{}, "T2 must be all Ts");
v->push_back(n);
add(v, rest...);
}

There is currently no way to avoid using both T and T2 (without modifying the call). The committee is considering potential improvements in this area, however, so something might make its way into the next standard.

With known number of args, forward variadic function in c

My question is, is it possible if I know the number of variadic args in the callee? For example, can f_wrapper be written to pass ... arguments to f?

The basic problem is that forwarding variadic arguments from one variadic function to another is a lexical issue, not a data processing issue. You must write a call to the wrapped function in which there is a compile-time representation of each argument, but you don't know until run time how many there will be, and you might not know their types.

If the space of acceptable argument lists is constrained enough, then the problem is pragmatically solvable. For example, if the wrapper will permit only a small number of variadic arguments, of only a small number of types (that it knows how to recognize), then it can analyze the variadic arguments at runtime to match them to the appropriate one of a list of possible calls to the wrapped function. Something like this:

int f_wrapper(int argc, ...) {
if (argc < 0 || argc > F_ARGS_MAX) {
// unsupported number of arguments
return -1;
}

int arg_values[F_ARGS_MAX];
// ... read argc variadic arguments into arg_values ...

switch (argc) {
case 0:
return f();
case 1:
return f(arg_values[0]);
// ...
}
}

Obviously, however, that gets impractical rather quickly, and it can't cope at all if there is no upper bound on the acceptable number of arguments.

As was suggested in comments, a variadic macro may be a more viable alternative, but that's not a complete substitute. For example, you cannot construct a pointer to a macro, you cannot use such a macro to provide an external interface to a function with internal linkage, the macro cannot host a static variable in the same way that a function does, ....

is there a c++ version of int..args

From C++11 and above, you can use parameter packs and store them in a std::initializer_list:

#include <iostream>
#include <initializer_list>

template <typename ...Args>
void fun(Args const&... args) {
std::initializer_list<int> arg_list { args... };
std::cout << "Number of arguments: " << arg_list.size() << std::endl;

for (auto const& i : arg_list)
std::cout << i << " ";
std::cout << std::endl;
}

int main() {
// Calling the varargs method with different number
// of parameters
fun(100); // one parameter
fun(1, 2, 3, 4); // four parameters
fun(); // no parameter
// fun(1, ""); // Error
}


Related Topics



Leave a reply



Submit