Reputation: 2184
In bellow sample code I'm trying to check if function arguments are pointers or not with std::is_pointer
it works fine if there is only one parameter, but how to make it work with more parameters, such as in parameter pack?
#include <type_traits>
#include <iostream>
class Test
{
public:
template<typename... Params>
void f(Params... params);
template<typename T, typename... Params>
auto sum(T arg, Params... params)
{
return arg + sum(params...);
}
template<typename T>
auto sum(T arg)
{
return arg;
}
int member = 1;
};
template<typename... Params>
void Test::f(Params... params)
{
// ERROR: too many template arguments for std::is_pointer
if constexpr (std::is_pointer_v<Params...>)
member += sum(*params...);
else
member += sum(params...);
std::cout << member;
}
int main()
{
Test ts;
// both fail
ts.f(1, 2);
ts.f(&ts.member, &ts.member);
// is that even possible?
ts.f(&ts.member, 2);
return 0;
}
I guess if parameters are not either all pointers or all not pointers then we have additional issue, but let's just assume all arguments are either pointers or not.
then what about if arguments are mix of pointers and non pointers anyway?
Upvotes: 1
Views: 1136
Reputation: 69892
The problem can be simplified (and the program made to work) by moving the detection of whether a param is a pointer into the variadic template function sum
.
example:
#include <type_traits>
#include <iostream>
class Test
{
public:
template<typename... Params>
void f(Params... params)
{
member += sum(params...);
std::cout << member << '\n';
}
template<typename... Params>
auto sum(Params... params)
{
auto contents = [](auto param)
{
using ParamType = std::decay_t<decltype(param)>;
if constexpr (std::is_pointer_v<ParamType>)
return *param;
else
return param;
};
return (contents(params) + ...);
}
int member = 1;
};
int main()
{
Test ts;
// both fail
ts.f(1, 2);
ts.f(&ts.member, &ts.member);
// is that even possible?
ts.f(&ts.member, 2);
return 0;
}
Expected output:
4
12
26
Upvotes: 1
Reputation: 155
For anyone using C++11/14, you can use the following solution.
// helper struct that checks the list
template<int N, typename... Args>
struct is_all_pointer_helper;
// N > 1, checks the head and recursively checks the tail
template<int N, typename Arg, typename... Args>
struct is_all_pointer_helper<N, Arg, Args...> {
static constexpr bool value =
std::is_pointer<Arg>::value &&
is_all_pointer_helper<N-1, Args...>::value;
};
// N == 1, checks the head (end of recursion)
template<typename Arg, typename... Args>
struct is_all_pointer_helper<1, Arg, Args...> {
static constexpr bool value = std::is_pointer<Arg>::value;
};
// N == 0, define your result for the empty list
template<> struct is_all_pointer_helper<0> {
static constexpr bool value = false;
};
// user interface
template<typename... Args>
struct is_all_pointer : is_all_pointer_helper<sizeof...(Args), Args...> {};
// C++14 only
template<typename... Args>
constexpr bool is_all_pointer_v = is_all_pointer<Args...>::value;
class Foo {};
int main()
{
cout << std::boolalpha << is_all_pointer<int*, char*, Foo*>::value << endl;
cout << std::boolalpha << is_all_pointer_v<int*, char, Foo*> << endl; //C++14
cout << std::boolalpha << is_all_pointer<>::value << endl;
}
Output:
true false false
Upvotes: 2
Reputation: 13424
You can use a fold expression:
#include <iostream>
#include <type_traits>
template <typename... Ts>
void test(Ts... ts) {
if constexpr ((std::is_pointer_v<Ts> && ...)) {
std::cout << "yes\n";
} else {
std::cout << "no\n";
}
}
int main() {
test(new int, new char, new int);
test(new int, new char, new int, 2);
}
The output of the program:
yes no
Be careful with your function template signature though - I would advise using Ts&&... ts
instead of Ts... ts
, because of how const char[]
s are treated. With my original example, test(new int, new char, new int, "hello");
will yield a yes
output, but with Ts&&... ts
, it will yield no
.
Upvotes: 6