Check if a type is passed in variadic template parameter pack
You're looking for std::disjunction
. It's specified in N4564 [meta.logical].
#include <type_traits>
template<typename T, typename... Ts>
constexpr bool contains()
{ return std::disjunction_v<std::is_same<T, Ts>...>; }
static_assert( contains<int, bool, char, int, long>());
static_assert( contains<bool, bool, char, int, long>());
static_assert( contains<long, bool, char, int, long>());
static_assert(not contains<unsigned, bool, char, int, long>());
Live demo
Or, adapted to a struct
template<typename T, typename... Ts>
struct contains : std::disjunction<std::is_same<T, Ts>...>
{};
Or, using fold expressions
template<typename T, typename... Ts>
struct contains : std::bool_constant<(std::is_same<T, Ts>{} || ...)>
{};
Live demo
Check if parameter pack contains a type
No, you have to use (partial) specialization with variadic templates to do compile-time computations like this:
#include <type_traits>
template < typename Tp, typename... List >
struct contains : std::true_type {};
template < typename Tp, typename Head, typename... Rest >
struct contains<Tp, Head, Rest...>
: std::conditional< std::is_same<Tp, Head>::value,
std::true_type,
contains<Tp, Rest...>
>::type {};
template < typename Tp >
struct contains<Tp> : std::false_type {};
There is only one other intrinsic operation for variadic templates and that is the special form of the sizeof operator which computes the length of the parameter list e.g.:
template < typename... Types >
struct typelist_len
{
const static size_t value = sizeof...(Types);
};
Where are you getting "it has serious compilation-time overhead" with boost mpl from? I hope you are not just making assumptions here. Boost mpl uses techniques such as lazy template instantiation to try and reduce compile-times instead of exploding like naive template meta-programming does.
Checking if variadic template parameters are unique using fold expressions
You approach doesn't really work because is_one_of
needs to be called with a type T
and all the remaining types not including T
. There's no way of expressing that with a fold expression over a single parameter pack. I suggest using specialization instead:
template <typename...>
inline constexpr auto is_unique = std::true_type{};
template <typename T, typename... Rest>
inline constexpr auto is_unique<T, Rest...> = std::bool_constant<
(!std::is_same_v<T, Rest> && ...) && is_unique<Rest...>
>{};
Usage:
static_assert(is_unique<>);
static_assert(is_unique<int>);
static_assert(is_unique<int, float, double>);
static_assert(!is_unique<int, float, double, int>);
live example on wandbox.org
(Thanks to Barry for the simplification that uses a fold expression.)
How can you statically check that a type T exists in a variadic template parameter list
Based on François' answer, here's a shorter version that avoids usage of std::tuple
and uses std::integral_constant
(via true/false_type
) and provides a C++14-style contains_v
alias. The general idea is the same though.
template <typename T, typename... Args>
struct contains;
template <typename T>
struct contains<T> : std::false_type {};
template <typename T, typename... Args>
struct contains<T, T, Args...> : std::true_type {};
template <typename T, typename A, typename... Args>
struct contains<T, A, Args...> : contains<T, Args...> {};
template <typename T, typename... Args>
constexpr bool contains_v = contains<T, Args...>::value;
You can use it like this:
static_assert(contains_v<float, float, double>,
"failure: float not among <float, double>"); // does not trigger
static_assert(contains_v<int, float, double>,
"failure: int not among <float, double>"); // triggers
How to check the type of passed arguments to variadic function
The only way I found is to make a helper function using SFINAE
//Basic function
template<typename T>
void allsame(T) {}
//Recursive function
template<typename T, typename T2, typename... Ts,
typename = std::enable_if_t<std::is_same<T, T2>::value>>
void allsame(T arg, T2 arg2, Ts... args)
{
allsame(arg2, args...);
}
You can then call it like so:
allsame(arg...);
The compiler will then throw an error if the types are not the same.
For 2), you could modfiy allsame
to return the type. The only drawback to this function is that it won't work if the type isn't default constructable.
template<typename T>
T allsame(T) { return{}; }
T allsame(T arg, T2 arg2, Ts... args)
Then, you can decltype(allsame(args...))
to get the type
How can I check type T is among parameter pack Ts...?
In your own implementation, one issue is that C++ doesn't allow partial specialization on function templates.
You can use the fold expression (which is introduced in C++17) instead of recursive function call.
template<class T1, class... Ts>
constexpr bool is_one_of() noexcept {
return (std::is_same_v<T1, Ts> || ...);
}
If you are using C++11 where fold expression and std::disjunction
are not available, you can implement is_one_of
like this:
template<class...> struct is_one_of: std::false_type {};
template<class T1, class T2> struct is_one_of<T1, T2>: std::is_same<T1, T2> {};
template<class T1, class T2, class... Ts> struct is_one_of<T1, T2, Ts...>: std::conditional<std::is_same<T1, T2>::value, std::is_same<T1, T2>, is_one_of<T1, Ts...>>::type {};
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.
In a variadic function template can the return type be deduced from the template parameter pack elements
I want to know if there is any way that this can be achieved.
No.
In C/C++ (that are statically typed languages) the type returned from a function must depends from the types of the arguments, not from the values.
So the types returned from the following calls
find_item(1, -1, "hello", 'Z', 10.03);
find_item(2, -1, "hello", 'Z', 10.03);
find_item(3, -1, "hello", 'Z', 10.03);
must be the same.
Point.
You can get around this rule returning a std::variant
(that can contain values of different types), or a std::any
(that can contain generic values), but a type that is determined independently from the received value.
Different if you pass the index of type/value you want (the first argument, in your case) as a template parameter.
I mean: different if you call find_item()
as follows
find_item<1>(-1, "hello", 'Z', 10.03);
find_item<2>(-1, "hello", 'Z', 10.03);
find_item<3>(-1, "hello", 'Z', 10.03);
Now find_item<1>()
can return a char const *
, find_item<2>()
can return a char
and find_item<3>()
can return a double
.
This is because find_item<1>()
, find_item<2>()
and find_item<3>()
are different functions, so can have different return types.
But... this way... we've almost obtained the std::get<>()
that extract values from a std::tuple
.
Unfortunately you can use this solution only when the index (the template parameter) is known compile time.
In other words, you can't make something as follows
for ( auto i = 1 ; i < 4 ; ++i )
{ // .............NO! ---V
auto value = find_item<i>(-1, "hello", 'Z', 10.03);
}
Related Topics
Conditionally Replace Regex Matches in String
Why How to Call a Non-Constexpr Function Inside a Constexpr Function
Throwing C++ Exceptions Across Dll Boundaries
C++ Class or Struct Compatiblity with C Struct
How to Differentiate (When Overloading) Between Prefix and Postfix Forms of Operator++? (C++)
Static Variable Initialization Over a Library
Why the Sequence-Operation Algorithms Predicates Are Passed by Copy
Does Calling a Destructor Explicitly Destroy an Object Completely
Is There an Non-Short Circuited Logical "And" in C++
How to Make a C++ Console Program Exit
Opencv Gtk+2.X Error - "Unspecified Error (The Function Is Not Implemented...)"