How can I check that arguments in parameter pack have type of either of float
, double
, integral, or a std::vector
of thereof?
For example T={int, long, std::vector<double>}
is fine,
while T={int, long, std::vector<long double>}
is not, because we don't allow std::vector
to be of long double
type.
I got this far
template<class ...T>
void foo(T... t)
{
static_assert(std::is_same<float, T...>::value
|| std::is_same<double, T...>::value
|| std::is_integral<T...>::value
/* || std::is_same<std::vector<float/double/integral>, T>::value ? */
, "unsupported type!");
}
and not sure how to express the restriction of std::vector
.
It would be nice to reuse the float/double/integral
check somehow, so that we wouldn't need to type them twice. Something like
bool basic_check = std::is_same<float, T...>::value
|| std::is_same<double, T...>::value
|| std::is_integral<T...>::value;
static_assert(basic_check
|| std::is_same<std::vector<basic_check>, T>
, "unsupported type!");
I also want the assert to succeed (i.e. pass the build) when T={}
.
Given a vector, you can determine its type with typeof() , or check if it's a specific type with an “is” function: is. character() , is.
There is no difference between using <typename T> OR <class T> ; i.e. it is a convention used by C++ programmers.
vector is a template class, which can be instantiated with a type, in the format: vector<int> , vector<double> , vector<string> . The same template class can be used to handle many types, instead of repeatably writing codes for each of the type.
A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.
You can create your own check, using template specialization. I've broadened the check to include long double
just to reduce the size of the code.
#include <type_traits>
#include <vector>
template<class T>
struct is_ok {
static constexpr bool value =
std::is_floating_point<T>::value ||
std::is_integral<T>::value;
};
template<class T>
struct is_ok<std::vector<T>> {
static constexpr bool value =
std::is_floating_point<T>::value ||
std::is_integral<T>::value;
};
Here is a demo:
#include <cstdio>
#define TEST(x) \
std::printf("%s: %s\n", #x, is_ok<x>::value ? "true" : "false")
int main() {
TEST(int);
TEST(float);
TEST(char *);
TEST(std::vector<int>);
TEST(std::vector<float>);
TEST(std::vector<char *>);
return 0;
}
Output:
int: true
float: true
char *: false
std::vector<int>: true
std::vector<float>: true
std::vector<char *>: false
First write a trait that tests one type:
template<class T>
struct is_ok : std::is_arithmetic<T> { };
template<class T, class A>
struct is_ok<std::vector<T, A>> : std::is_arithmetic<T> { };
Then test that the trait holds true for every type in the pack. I prefer to use @Columbo's bool_pack
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>
void foo(T... t)
{
static_assert( all_true<is_ok<T>::value...>::value, "unsupported type!");
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With