How to make a variadic is_same?
Use template recursion:
template<typename T, typename... Rest>
struct is_any : std::false_type {};
template<typename T, typename First>
struct is_any<T, First> : std::is_same<T, First> {};
template<typename T, typename First, typename... Rest>
struct is_any<T, First, Rest...>
: std::integral_constant<bool, std::is_same<T, First>::value || is_any<T, Rest...>::value>
{};
static_assert(is_any<int, char, double, int>::value, "error 1"); // OK
static_assert(is_any<int, char, double, short>::value, "error 2"); // error
Is it possible to use 'enable_if' and 'is_same' with variadic function templates?
Yes. You can use a fold expression in C++17:
template <typename T, typename... U>
typename std::enable_if<(std::is_same<U, float>::value && ...), void>::
type testFunction(T a, U... bs) {
std::cout << "bs are floats\n";
}
In C++11, you can reimplement std::conjunction
:
template<class...> struct conjunction : std::true_type { };
template<class B1> struct conjunction<B1> : B1 { };
template<class B1, class... Bn>
struct conjunction<B1, Bn...>
: std::conditional_t<bool(B1::value), conjunction<Bn...>, B1> {};
template <typename T, typename... U>
typename std::enable_if<
std::conjunction_v<std::is_same<U, float>...>,
void
>::type testFunction(T a, U... bs) {
std::cout << "bs are floats\n";
}
How do I make sure Types in a variadic Tuple are identical?
You can check all the types are identical or not with the help of fold expression (since C++17).
E.g.
template <typename T, // the 1st type
typename... Args, // subsequent types
typename enable_if<is_arithmetic_v<T>>::type* = nullptr, // check for arithmetic type
typename enable_if<(is_same_v<T, Args> && ...)>::type* = nullptr> // check all the types are identical or not
auto toString(tuple<T, Args...> tup)
{
std::stringstream ss;
std::apply([&ss](auto&&... args) {((ss << args << ";"), ...); }, tup);
return ss.str();
}
LIVE
How can I make this variadic template code shorter using features from C++14 and C++1z?
#include <type_traits>
template <typename F, typename... Ts>
constexpr bool is_one_of = (std::is_same<F, Ts>{} || ...);
template <typename...>
constexpr bool is_unique = true;
template <typename F, typename... Ts>
constexpr bool is_unique<F, Ts...> = is_unique<Ts...> && !is_one_of<F, Ts...>;
DEMO
Limit allowed COM Interfaces by using template function with limited variadic parameters (std::is_same)
Try with
template <class TypeOther, class =
std::enable_if_t<(std::is_same_v<Types, TypeOther> || ...)>>
WithCOMptrbase(TypeOther* ptr)
: ptr_(cQueryInterface<T>(ptr))
{}
I mean... you're using three ellipsis instead of one (remove the ellipsis after ::value
and the one after Types
) and you need an additional couple of parentheses.
Off topic: are you sure that works
template <class T, class ... Types, class = typename
std::enable_if<std::is_base_of<IUnknown, T>::value>::type>
class WithCOMptrbase
?
SFINAE through a default type after a variadic list?
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
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.
C++ function with a viariable number of arguments of a certain type
If the compiler supports C++ 20 then you can write for example
#include <type_traits>
template <typename T, uint16_t dimension>
class Vector
{
public:
template <typename... Ts>
Vector( Ts &&... args ) requires ( sizeof...( args ) == dimension ) && std::conjunction_v<std::is_same<T, std::decay_t<Ts>>...>
{
}
};
//...
Vector<float, 5> v( 1.1f, 2.2f, 3.3f, 4.4f, 5.5f );
Or as @HolyBlackCat wrote in a comment you may also write
template <typename T, uint16_t dimension>
class Vector
{
public:
template <typename... Ts>
Vector( std::same_as<T> auto ...args ) requires( sizeof...( args ) == dimension )
{
}
};
Enforce variadic template of certain type
We can use SFINAE to ensure that all U
types are the same as T
. An important thing to note is that U
is not just one type as you imply, but a list of possibly disparate types.
template<class... U, std::enable_if_t<all_same<T, U...>::value>* = nullptr>
Foo(T first, U... vals) {
std::cout << "Called multiple argument ctor" << std::endl;
// [...]
}
std::enable_if_t
is from C++14. If that's not an option for you, just use std::enable_if
.
typename std::enable_if<all_same<T, U...>::value>::type* = nullptr>
all_same
can be implemented in a bunch of different ways. Here's a method I like using boolean packs:
namespace detail
{
template<bool...> struct bool_pack;
template<bool... bs>
//if any are false, they'll be shifted in the second version, so types won't match
using all_true = std::is_same<bool_pack<bs..., true>, bool_pack<true, bs...>>;
}
template <typename... Ts>
using all_true = detail::all_true<Ts::value...>;
template <typename T, typename... Ts>
using all_same = all_true<std::is_same<T,Ts>...>;
Related Topics
Error: Passing 'Const …' as 'This' Argument of '…' Discards Qualifiers
When Is It Safe to Call This-> in Constructor and Destructor
Pointing to a Function That Is a Class Member - Glfw Setkeycallback
Iter_Swap() Versus Swap() -- What's the Difference
Counting the Number of Lines in a Text File
C++ Linking Error After Upgrading to MAC Os X 10.9/Xcode 5.0.1
Do Negative Numbers Return False in C/C++
Openmp Nested Parallel for Loops VS Inner Parallel For
How to Use Memcpy in C++ to Copy Classes That Have No Pointers or Virtual Functions
How to Erase & Delete Pointers to Objects Stored in a Vector
Getchar_Unlocked( ) VS Scanf() VS Cin
Do I Really Have to Worry About Alignment When Using Placement New Operator
Static Global Variables in C++
Forcing Nvidia Gpu Programmatically in Optimus Laptops
Header File Inclusion Static Analysis Tools