My nullPointcheck function:
template<typename T, typename... Args>
bool __nullPointCheck(T first, Args... args)
{
bool ret = true;
va_list vl;
auto n = sizeof...(args);
va_start(vl, n);
for (auto i = 0; i <= n; ++i)
{
auto p = va_arg(vl, T);
if (!p)
{
ret = false;
}
}
va_end(vl);
return ret;
}
but I'm getting the ndk build error as follows:
'va_start' used in function with fixed args
va_start(vl, n);
when I change the second param in va_start to first as follows:
va_start(vl, first);
ndk-build export the error as follows:
'va_start' used in function with fixed args
va_start(vl, first);
^
E:/ANDROID_HOME/android-ndk-r10c/toolchains/llvm-3.5/prebuilt/windows-x86_64/bin
\..\lib\clang\3.5\include\stdarg.h:33:29: note:
expanded from macro 'va_start'
#define va_start(ap, param) __builtin_va_start(ap, param)
There are no errors in vs2013, but the code can's pass ndk-build stage
va_start etc. can only be used in a function whose prototype ends in ...); . This is different to a parameter pack. Your code uses a parameter pack. The syntax for using parameter packs is different to the syntax for variadic functions.
I am assuming your function should return true if and only if all arguments are non-null pointers. One way to implement your function would be:
inline constexpr bool nullPointCheck() { return true; }
template<typename T, typename... Args>
constexpr bool nullPointCheck(T&& first, Args&&... args)
{
return first && nullPointCheck(args...);
}
rontgen's answer is also good.
You can actually use this function to check if any arbitrary argument list is all true. I used universal references so that copies are not made of the arguments; this makes no difference for pointers but may make a difference for more complicated types.
To limit the function to only accept pointers, change T&& to T *. (Leave Args&& as it is). If you also want to accept the literal nullptr then you also need an overload:
inline constexpr bool nullPointCheck(std::nullptr_t) { return false; }
because nullptr actually does not deduce to any T *.
My solusion which can pass the stage of compilation is as follows:
template<typename T, typename... Params, std::size_t N = sizeof...(Params)>
static bool nullPointCheck(Params... params)
{
std::array<T, N> arr = { params... };
for (auto point : arr)
{
if (!point)
{
return false;
}
}
return true;
}
Related
I tried to make emplace the same as it is done in std::vector, but I get errors that I can not understand. This code does NOT work, if I do not explicitly specify the type in the templates. I get the following error:
error C2780: 'void AVLTree::emplace(Args &&...,bool)': expects 2 arguments - 3 provided
In the process of trying to solve the problem I got the impression that the compiler takes the type of the first argument and substitutes it as the type of all arguments (except the last one). Also i tried to emplace_back with this arguments to std::vector and didn't get any errors. Compiler from last version MSVC 22.
main
AVLTree<Student> tree_balance, tree_non_balance;
tree_balance.emplace(QString("Anikeeva"), QVector<int>{2, 4, 5, 2, 3}, true);
AVLTree.h
template <class... Args>
void emplace(Args&& ...args, bool need_balance = true){
INFO info(std::forward<Args>(args)...);
add(std::move(info), need_balance);
}
void add(INFO&& k, bool need_balance = true){
root = insert(root, std::forward<INFO>(k), need_balance);
}
Node<INFO>* insert(Node<INFO>* p, INFO&& k, bool need_balance = true)
{
if( !p ) {
return new Node(std::forward<INFO>(k));
}
if( k<p->key )
p->left = insert(p->left,std::forward<INFO>(k), need_balance);
else
p->right = insert(p->right,std::forward<INFO>(k), need_balance);
if (need_balance) {
return balance(p);
}
else {
return p;
}
}
Student.h
Student(QString&& _FIO, std::vector<int>&& _arr) noexcept;
Student(const QString& _FIO, const std::vector<int>& _arr) noexcept;
It's because the compiler cannot decide whether the boolean it sees in
tree_balance.emplace(QString("Anikeeva"), QVector<int>{2, 4, 5, 2, 3}, true);
should be part of Args&&.... The error message you got is not very helpful, but the rule is that a parameter pack must be the last argument, so that the compiler can unambiguously take any remaining arguments to be part of the pack. So yes, putting the boolean first would be valid, but then it can't have a default value. Here is a strategy ("tag dispatch") you could use to get around this limitation:
struct unbalanced_t {};
inline constexpr unbalanced_t unbalanced {};
template <class... Args>
void emplace(Args&& ...args) {
INFO info(std::forward<Args>(args)...);
add(std::move(info), true);
}
// To be called as tree.emplace(unbalanced, ...);
template <class... Args>
void emplace(unbalanced_t, Args&& ...args) {
INFO info(std::forward<Args>(args)...);
add(std::move(info), false);
}
Variadic template is greedy, so default parameters afterward cannot be set explicitly.
If you can, use tuple instead (so more similar to std::pair's constructor with std::piecewise_construct_t):
template <class Tuple>
void emplace(Tuple&& args, bool need_balance = true)
{
add(std::make_from_tuple<INFO>(forward<Tuple>(args)), need_balance);
}
With usage similar to:
tree_balance.emplace(std::tuple{QString("Anikeeva"), QVector<int>{2, 4, 5, 2, 3}} /*, true*/);
(And so, tuple can have bool as last argument)
Else, you can still drop bool need_balance parameter, and check last template argument or Args
template <class... Args>
void emplace(Args&& ...args)
{
if constexpr (std::is_same_v<bool, decltype((args, ...))>){
bool need_balance = (args, ...); // last value
// Drop last parameter of pack with a custom create_tuple_without_last
add(INFO(std::make_from_tuple<INFO>(create_tuple_without_last(std::forward<Args>(args)...)))), need_balance);
} else {
bool need_balance = false;
add(INFO(std::forward<Args>(args)...), need_balance);
}
}
I am trying to solve this problem in C++ TMP where in i need to convert one parameter pack types into another, and then convert back the types and also values. The conversion back part is based on a boolean criteria that whether an arg in Args... was transformed or not in the first place.
Basically, i have a pack(Args...). First, i transform this (for each args[i], call a transform function). It works like this:
For each arg in Args..., just create same type in transformed_args... unless it is one of following, in that case do following conversions:
Type In Args...
Type In transformed_Args...
SomeClass
shared_ptr to SomeClass
std::vector of SomeClass
std::vector of shared_ptr to SomeClass
everything else remains the same for ex:
int remains int
std::string remains std::string
I achieve this by template specialization, of course
For the next part, i take transformed_args..., publish a class and a functor. I receive call back on this functor from(C++generated Python using Pybind, not important though). Relevant bits of that class look like this...
template<typename C, typename...transformed_args..., typename... Args>
class SomeTemplateClass
{
MethodWrapper<C,void, Args...> func;
//.....
void operator()(transformed_args... targs)
{
//....
(*func.wrapped_method_inside)(transform_back_magic(targs)...) // this is want i want to achieve.
//transform_back_magic(targs)... is a plaeholder for code that checks if type of args[i]... != type of targs[i]... and then calls a tranform_back specialization on it else just return args[i].val
}
}
targs are in transformed_args... format, but underlying C++ function they are aimed for expects Args...
template<typename... Args, typename... transformed_args, ........whatever else is needed>
transform_back_magic(....)
{
if(Args[i].type != transformed_args[i].types)
tranform_back(targs[i]...);
}
the tranform_back function template logic is specialized for different cases and all logic is in place. But how to invoke that based on this boolean criteria is hitting my TMP knowledge limits. I just got started not many weeks ago.
Here i am listing down what i have created so far.
First of all this is what i need in pseudo code
template<typename C, typename... transformed_args, typename... Args>
class SomeTemplateClass
{
MethodWrapper<C,void, Args...> func;
void operator(transformed_args... targs)
{
**//In pseudo code, this is what i need**
Args... params = CreateArgsInstanceFromTransformedArgs(targs);
(*func.wrapped_method_inside)(params...);
}
}
In my attempt to implement this, so far I have decided on creating a tuple<Args...> object by copying data from targs(with conversions where ever required)
void operator(transformed_args... targs)
{
//....
auto mytup = call1(std::tuple<args...>(), std::make_index_sequence<sizeof...(Args)>,
std::make_tuple(targs...), targs...);
// mytup can be std::tuple<Args...>(transform_back(1st_targs), transform_back(2nd_targs)....). Once available i can write some more logic to extract Args... from this tuple and pass to(*func.wrapped_method_inside)(....)
(*func.wrapped_method_inside)(ArgsExtractorFromTuple(mytup)); // this part is not implemented yet, but i think it should be possible. This is not my primary concern at the moment
}
//call1
template<typename... Args, typename... Targs, std::size_t... N>
auto call1(std::tuple<Args...> tupA, std::index_sequence<N>..., std::tuple<Targs...> tupT, Targs ..)
{
auto booltup = tuple_creator<0>(tupA, tupT, nullptr); // to create a tuple of bools
auto ret1 = std::make_tuple<Args...>(call2(booltup, targs, N)...); // targs and N are expanded together so that i get indirect access to see the corresponding type in Args...
return ret1;
}
// tuple_creator is a recursive function template with sole purpose to create a boolean tuple.
// such that std::get<0>(booltup) = true,
//if tuple_element_t<0,std::tuple<Args...>> and tuple_element_t<0,std::tuple<targs...>> are same types else false
template<size_t I, typename... Targs, typename... Args>
auto tuple_creator(std::tuple<Args...>tupA, std::tuple<Targs...>tupT, std::enable_if_t<I == sizeof...(targs)>*)
{
return std::make_tuple(std::is_same<std::tuple_element_t<I-1, std::tuple<Targs...>>, std::tuple_element_t<I-1, std::tuple<Args...>>>::value);
}
template<size_t I = 0, typename... Targs, typename... Args>
auto tuple_creator(std::tuple<Args...>tupA, std::tuple<Targs...>tupT, std::enable_if_t<I < sizeof...(targs)>*)
{
auto ret1 = tuple_creator<I+1>(tupA, tupT, nullptr);
if(!I)
return ret1;
auto ret2 = std::is_same<std::tuple_element_t<I-1, std::tuple<Targs...>>, std::tuple_element_t<I-1, std::tuple<Args...>>>::value;
return std::tuple_cat(ret1, std::make_tuple(ret2));
}
template<typename TT, typename Tuple>
auto call2(Tuple boolyup, TT t, std::size_t I)
{
auto ret = transform_back<std::get<I>(booltup)>(t); // error: I is not a compile time constant
return ret;
}
transform_back is a template that uses a bool template param and enable_if based specialization to decide whether transform an argument back or not
below are the transform_back specialization for std::vector. Similarly i have others for when T = Class etc and so on
template<bool sameTypes, typename T>
std::enable_if_t<(is_vector<T>::value, is_shared_ptr<typename T::value_type>::value &&
is_class<remove_cvref_t<typename T::value_type_element_type>>::value
&& sameTypes), T>
transform_back(T val) // it was never transfoemd in first place, return as is
{
return val;
}
template<bool sameTypes, typename T>
std::enable_if_t<(is_vector<T>::value, is_shared_ptr<typename T::value_type>::value
&& is_class<remove_cvref_t<typename T::value_type_element_type>>::value
&& !sameTypes),
typename std::vector<typename T::value_type::element_type>>
transform(T val)
{
std::vector<T::value_type::element_type> t;
for(int i = 0 ; i < val.size(); ++i)
{
typename T::value_type::element_type obj = *val[i];
t.push_back(obj);
}
return t;
}
Both these specialization are same and only differ on sameTypes boolean variable
This code currently errors out in call2 method while trying to using
std::get
auto ret = transform_back<std::get<I>(booltup)>(t); // error: I is not a compile time constant
How can you help?
1)What could be the work around to std::get issue here? Just cant figure out a way to fit in std::size_t as template arg here instead of function arg to make it work at compile time.
Other than this:
2)If you can suggest an alternative approach to implement from top level.
Args... params = CreateArgsInstanceFromTransformedArgs(targs);
That would be great. The path i took is not very convincing personally to me.
If I understand correctly, you might do something like:
template <typename> struct Tag{};
std::shared_ptr<SomeClass> transform_to(Tag<std::shared_ptr<SomeClass>>, const SomeClass& s)
{
return std::make_shared<SomeClass>(s);
}
std::vector<std::shared_ptr<SomeClass>> transform_to(Tag<std::vector<std::shared_ptr<SomeClass>>>, const std::vector<SomeClass>& v)
{
std::vector<std::shared_ptr<SomeClass>> res;
res.reserve(v.size());
for (const auto& s : v) {
res.emplace_back(std::make_shared<SomeClass>(s));
}
return res;
}
const SomeClass& transform_to(Tag<SomeClass>, const std::shared_ptr<SomeClass>& s)
{
return *s;
}
std::vector<SomeClass> transform_to(Tag<std::vector<SomeClass>>, const std::vector<std::shared_ptr<SomeClass>>& v)
{
std::vector<SomeClass> res;
res.reserve(v.size());
for (const auto& s : v) {
res.emplace_back(*s);
}
return res;
}
template <typename T>
const T& transform_to(Tag<T>, const T& t) { return t; } // No transformations
And then
std::function<void (Args...)> func;
template <typename ... transformed_args>
void operator () (transformed_args... targs) const
{
func(transform_to(Tag<Args>(), targs)...);
}
Just explaining the use case here to add some context. Consider these three methods in C++ each represented with the function pointer SomeTemplateClass::func:
void foo(vector<shared_ptr<SomeClass>>) // 1
// Args... = vector<shared_ptr<SomeClass>>, Targs... = vector<shared_ptr<SomeClass>>
void foo(vector<SomeClass>) // 2
// Args... = vector<SomeClass>, Targs... = vector<shared_ptr<SomeClass>>
void foo(vector<SomeClass>, vector<shared_ptr<SomeClass>>) // 3
// Args... = vector<SomeClass>, vector<shared_ptr<SomeClass>>, Targs... = vector<shared_ptr<SomeClass>>, vector<shared_ptr<SomeClass>>
One instance each of SomeTemplateClass is exposed to Python via Pybind. I do these transformations so that when foo is called from Python, any arg vector<T>(in C++) is received as vector<shared_ptr<T>> in SomeTemplateClass functor. This helps in to get handle to previously created objects T that i need.
But as you can see from 3 cases for foo, foo(vector<shared_ptr<T>>) does not need to be transformed to and subsequently not need to be transformed back. The case of 'tranform_to'is easily handled with template specialization, but while transforming back, vector<shared_ptr<T>> cant be blindly converted back to vector<T>. So (transform(targs...)) needs an additional logic to transform a particular arg (or targ) only when targ[i]::type != arg[i]::type
Building on Jarod's answer, i rather need something like this where in transform_to method for vector<shared_ptr> is further divided in two possible templates
template<bool wasOriginallyTransformed>
enable_if<!wasOriginallyTransformed, std::vector<std::shared_ptr<SomeClass>> transform_to(Tag<std::vector<SomeClass>>, const std::vector<std::shared_ptr<SomeClass>>& v)
{
return v;
}
template<bool wasOriginallyTransformed>
enable_if<!wasOriginallyTransformed, std::vector<<SomeClass>
transform_to(Tag<std::vector<SomeClass>>, const std::vector<std::shared_ptr<SomeClass>>& v)
{
std::vector<SomeClass> res;
res.reserve(v.size());
for (const auto& s : v) {
res.emplace_back(*s);
}
return res;
}
#include <stdarg.h>
template<typename... Args>
void Func(Args... args)
{
// WANT: Get the address of the first argument
// TRIED:
// va_list vargs = (char*)&(args);
// va_list vargs = (char*)&(args)...;
// va_list vargs = (char*)&(args...);
// GOT:
// 'args': parameter pack must be expanded in this context
}
I'm writing a function that accepts N arguments and does something with all of them. And for that I want to grab the address of the first element of the variadic argument list.
After that, to my knowledge the va_arg macro dereferences the pointer and shifts va_list type object with the size of assumed type
Edit: I could do probably something like this:
template<typename... Args>
void Func(int arg1, Args... args)
{
// Code
}
But, it would result in more lines of code which I don't want.
Simpler would be to split argument in signature:
template <typename T, typename... Ts>
void Func(T arg, Ts... args)
{
// WANT: Get the address of the first argument
T* p = &arg;
}
else
template <typename... Ts>
void Func(Ts... args)
{
// WANT: Get the address of the first argument
auto* p = std::get<0>(std::make_tuple(&args...));
}
I try to pass to a variadic template function a list of references and pass it to another function. The code that I wrote is the following:
template <typename T>
void fun(cv::Point_<T> & pt) { pt.x++; pt.y++; }
template <class ... args>
void caller(args & ... list) {
typedef typename std::tuple_element<0, std::tuple<args...> >::type T;
std::array<std::reference_wrapper<T>, sizeof...(list)> values {list ... };
for(int i=0; i<values.size(); i++)
fun(values[i]);
}
then I call the function caller in this way:
cv::Point2f a, b, c;
caller(a, b, c);
the compiler give me the following error:
No matching function for call to 'fun'
Candidate template ignored: could not match 'Point_' against 'reference_wrapper'
what I missing?
Although std::reference_wrapper<T> has an implicit conversion to T&, you cannot use both an implicit conversion and template argument deduction at the same time, and template argument deduction is necessary to call fun.
Try
fun(values[i].get());
Even simpler is
template <typename...Args>
void caller(Args&...args)
{
auto tmp = { (func(args),0)..., 0 };
}
This uses the fact that parameter pack expansion can occur in braced init lists. Since func() returns void, we cannot simply use { func(args)... }, but use (func(args),0) to have an int. Finally, the last 0 is to ensure that the code compiles (and does nothing) in case of an empty parameter pack.
You can generalise this and write a template that calls a given generic function for every element of a pack:
template <typename Func, typename...Args>
void call_for_each(Func &&func, Args&&...args)
{
auto unused = { (func(std::forward<Args>(args)),0)...,0 };
}
which may be used like this (C++14)
int main()
{
int a=1;
double b=2.4;
auto func = [](auto&x) { std::cout<<' '<<x++; };
call_for_each(func,a,b);
std::cout<<'\n';
call_for_each(func,a,b);
std::cout<<'\n';
}
This uses a C++14 lambda (taking an auto argument). Note that the parameter pack must come last among the template parameters of call_for_each.
Since the goal of this might be to iterate over all args, here's a more generic solution. We are going to implement for_pack:
template<typename... Args, typename F>
void for_pack(F function, Args&&... args) {
using expand = int[];
(void)expand{(function(std::forward<Args>(args)), void(), 0)..., 0};
}
This will execute function for every args in Args.
Now, your function caller is much more trivial to implement:
template <typename... args>
void caller(args&... list) {
for_pack([&](cv::Point_<T>& arg){
fun(arg);
}, list...);
}
Since a google search for "c++ pass reference parameters to variadic template" gives this as first result, I'll put this generic solution here.
struct HH { /*...*/ void change_me() { /*...*/ } };
template<typename...T> void parms_r_refs() {}
template<typename H, typename...T> void parms_r_refs(H &h, T&...t) { h.change_me(); parms_r_refs(t...); }
template<typename...T> void parms_r_refs(T&...t) { parms_r_refs(t...); }
HH a, b, c;
..
parms_r_refs(a, b, c);
..
I have a template function that takes a variable number of arguments. Since you can't force the arguments to be of a certain type I would like at least to force the number of arguments not to be higher that a compile-time determined number(e.g. 10).
Is it possible to make to compiler give an error if a template function with a parameter pack has the number of arguments higher than a compile-time determined value?
template <class ...Args>
void setRequestArguments(const Args&... args)
{
const std::vector<QGenericArgument> vec = { args... };
qDebug() << sizeof...(args);
// Do stuff...
// for (unsigned i = 0; i < vec.size(); ++i) {
// qDebug() << vec[i].name();
// }
}
What I want to use it for is for a generic container for all arguments in an QMetaObject::invokeMethod wrapper function.
To make the function not callable when there's too many arguments, you can constraint the function with sfinae. That way, if there's another overload that accepts more arguments, the compiler will be able to select the correct overload.
A simple std::enable_if with the condition will suffice:
template <class ...Args, std::enable_if_t<(sizeof...(Args) <= 10)>* = nullptr>
void setRequestArguments(const Args&... args)
{
const std::vector<QGenericArgument> vec = {args... };
}
For the sake of readability, you can put the constraint in the trailing return type of your function:
template <class ...Args>
auto setRequestArguments(const Args&... args) -> std::enable_if_t<(sizeof...(args) <= 10)>
{
const std::vector<QGenericArgument> vec = {args... };
}
Here's an updated version for C++20 using requires and terse template syntax:
auto setRequestArguments(const auto&... args) requires (sizeof...(args) <= 10) -> void {
const std::vector<QGenericArgument> vec = {args... };
}
Is it possible to make to compiler give an error if a template function with a parameter pack has the number of arguments higher than a compile-time determined value?
Yes, use static_assert:
template <class ...Args>
void setRequestArguments(const Args&... args)
{
static_assert(sizeof...(args) <= 10, "You can't have more than 10 arguments!");
//Stuff...
}