How to create a type list (for variadic templates) that contains n-times the same type?
I would do it this way:
template<typename, typename>
struct append_to_type_seq { };
template<typename T, typename... Ts, template<typename...> class TT>
struct append_to_type_seq<T, TT<Ts...>>
{
using type = TT<Ts..., T>;
};
template<typename T, unsigned int N, template<typename...> class TT>
struct repeat
{
using type = typename
append_to_type_seq<
T,
typename repeat<T, N-1, TT>::type
>::type;
};
template<typename T, template<typename...> class TT>
struct repeat<T, 0, TT>
{
using type = TT<>;
};
As a small test:
#include <type_traits>
#include <tuple>
template<typename... Ts>
struct X { };
int main()
{
repeat<double, 5, std::tuple>::type t = std::make_tuple(1., 2., 3., 4., 5.);
static_assert(
std::is_same<
decltype(t),
std::tuple<double, double, double, double, double>
>::value, "!");
repeat<double, 3, X>::type y;
static_assert(
std::is_same<decltype(y), X<double, double, double>>::value, "!");
}
Finally, a live example.
How to create a variadic struct that takes a variadic invocable of the same arity as the ctor parameter?
std::tuple
(with std::apply
) might help:
template <std::derived_from<IUnknown>... Ts>
struct AutoManagedCOMObj
{
std::tuple<Ts*...> tuple_ptrs;
template<std::invocable<Ts**...> Invocable>
AutoManagedCOMObj(Invocable initializer)
{
HRESULT hr = std::apply([&](auto*&... ptrs){ return initializer(&ptrs...);},
tuple_ptrs);
if (FAILED(hr)) exit(hr);
}
~AutoManagedCOMObj()
{
std::apply([](auto*... ptrs){ (ptrs->Release(), ...); }, tuple_ptrs);
}
};
Ensuring that a variadic template contains no duplicates
This can be written with the help of two metafunctions.
First, IsContained
checks whether a type appears in a type list.
template <typename T, typename... List>
struct IsContained;
template <typename T, typename Head, typename... Tail>
struct IsContained<T, Head, Tail...>
{
enum { value = std::is_same<T, Head>::value || IsContained<T, Tail...>::value };
};
template <typename T>
struct IsContained<T>
{
enum { value = false };
};
Second, IsUnique
checks whether a type list contains no duplicates. It uses IsContained
to check all element combinations.
template <typename... List>
struct IsUnique;
template <typename Head, typename... Tail>
struct IsUnique<Head, Tail...>
{
enum { value = !IsContained<Head, Tail...>::value && IsUnique<Tail...>::value };
};
template <>
struct IsUnique<>
{
enum { value = true };
};
With these tools, the static assertion is then very simple:
template <typename... Ts>
struct NoDuplicates
{
static_assert(IsUnique<Ts...>::value, "No duplicate types allowed");
};
Best way to generate a variadic argument list containing N arguments of a given type?
Something along these lines, perhaps:
template <typename T, size_t dummy>
using EatIndex = T;
template <typename T, std::size_t... I>
Bag<EatIndex<T, I>...> MakeBagN(std::index_sequence<I...>);
template<size_t N, typename T>
using BagN = decltype(MakeBagN<T>(std::make_index_sequence<N>()));
template<size_t N, typename T>
class UniBag : public BagN<N, T> {};
Demo
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.
Expand a type N times in template parameter
You can use std::index_sequence
:
template<std::size_t N, typename = std::make_index_sequence<N>>
struct A;
template<std::size_t N, std::size_t... S>
struct A<N, std::index_sequence<S...>> {
std::function<std::size_t(decltype(S)...)> foo;
};
Live example
If you like, you could also define to what type it expands:
template<typename T, std::size_t N, typename = std::make_index_sequence<N>>
struct A;
template<typename T, std::size_t N, std::size_t... S>
struct A<T, N, std::index_sequence<S...>> {
template<std::size_t>
using type = T;
std::function<std::size_t(type<S>...)> foo;
};
C++ variadic templates with type and non-type argument mixing for recursive inheritance
It's not possible. You'll have to settle for one of the following:
Foo<Bar<int, 5>, Bar<double, 7>> foo_1;
Foo<int, Bar<5>, double, Bar<7>> foo_1;
// ...?
If the values are always integral, you could also try this:
Foo<int[5], double[7]> foo_1;
And then extract elemenet types & extents from each argument.
Variadic template declaration from single integer argument?
You can write a meta-function that accepts N
, base_t
, and SomeOtherClass
, and recursively calls itself with a smaller N
, each time tacking on base_t
to the end of a growing parameter pack:
template <int N, typename T, template<typename...> typename C, typename ...Ts>
struct expand {
using type = typename expand<N-1, T, C, T, Ts...>::type;
};
For the base case, when N
goes down to 0, the meta-function yields SomeOtherClass
instantiated with the parameter pack of N
base_t
types:
template <typename T, template<typename...> typename C, typename ...Ts>
struct expand<0, T, C, Ts...> {
using type = C<Ts...>;
};
Also, convenience alias is nice to avoid having to say typename
at the call site:
template <int N, typename T, template<typename...> typename C>
using expand_t = typename expand<N, T, C>::type;
Now at the call site you can write:
expand_t<N, base_t, SomeOtherClass> foo;
// equivalent to
// SomeOtherClass< base_t, base_t, ..., base_t > foo;
// ^^^ N times ^^^
Here's a demo.
Related Topics
How to Declare Array with Auto
What Is the Modern, Correct Way to Do Type Punning in C++
How to Get Python Exception Text
How to Use a Lambda Expression as a Template Parameter
C++ Frontend Only Compiler (Convert C++ to C)
Global Variable "Count" Ambiguous
What Strategies Have You Used to Improve Build Times on Large Projects
Passing Member Function Pointer to Member Object in C++
Brute-Force, Single-Threaded Prime Factorization
Why Don't I Need to Specify "Typename" Before a Dependent Type in C++20
Is Extern "C" Only Required on the Function Declaration
Is There a Reason Why Not to Use Link-Time Optimization (Lto)
Qtcreator: No Valid Kits Found
Reading "Integer" Size Bytes from a Char* Array
Std::Unordered_Map::Find Using a Type Different Than the Key Type