How to Make a Variadic Is_Same

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



Leave a reply



Submit