given Variadic templates data structure as below ( code from Eli Bendersky's website):
template <class... Ts> struct tuple {};
template <class T, class... Ts>
struct tuple<T, Ts...> : tuple<Ts...> {
tuple(T t, Ts... ts) : tuple<Ts...>(ts...), tail(t) {}
T tail;
};
we are able to define something like
tuple<double, uint64_t, const char*> t1(12.2, 42, "big");
Then how to define a template structure that could accept following signature?
Foo<tuple<int,double>, tuple<double,int,long> ..., tuple<std::string>> foo;
I think it would be like this:
template<tuple<class... Ts>... Tuples>
struct VariadicTuples {};
but it cannot compile. is that because the class in the Variadic templates cannot be Variadic templates? If so, How to make this work?
You simply cannot write that, syntactically. What would Ts hold in that situation? It would be different for each type in Tuples so it wouldn't really be usable.
What you can do instead is take advantage of Columbo's bool_pack trick:
template <bool...> struct bool_pack;
template <bool... v>
using all_true = std::is_same<bool_pack<true, v...>, bool_pack<v..., true>>;
To simply static_assert that all the Tuples are, in fact, tuples and then have VariadicTuples be a simple variadic class template:
template <typename > struct is_a_tuple : std::false_type { };
template <typename... T> struct is_a_tuple<tuple<T...>> : std::true_type { };
template <typename... Tuples>
struct VariadicTuples {
static_assert(all_true<is_a_tuple<Tuples>::value...>::value, "!");
};
Related
I am new to template meta programming and was trying to create a program that would find if a parameter pack has consecutive same type names. For example <int, int>, <int, char, char> would return true and <int,char> and <int, char, int> would not.
I managed to write this piece of code but it seems to be comparing each value of parameter pack with itself. I am just looking for a way to iterate through the values of parameter pack to compare with it's consecutive element.
template<typename T, typename U>
struct sameTypename{
enum {value = false};
};
template<typename T>
struct sameTypename<T, T>{
enum {value = true};
};
template <typename T, typename ...args>
struct consTypename{
enum {value = (sameTypename<consTypename<args...>, consTypename<args...>>::value)};
};
template <typename T>
struct consTypename<T, T>{
enum {value = true};
};
template <typename T>
struct consTypename<T>{
enum {value = false};
};
Here you go:
#include <type_traits>
template <typename ...P> struct has_adjacent_same_types : std::false_type {};
template <typename A, typename B, typename ...P> struct has_adjacent_same_types<A, B, P...>
: std::bool_constant<std::is_same_v<A,B> || has_adjacent_same_types<B, P...>::value> {};
I used : std::false_type {}; and : std::bool_constant<X> {}; instead of
{enum{value = false};}; and {enum{value = X};}; respectively, but that's simply a matter of preference.
Some of the features I used are from C++17. If you're using an older version, note that:
std::bool_constant and std::is_same_v are available only starting from C++17 (but that you can use std::integral_constant and std::is_same<>::value before).
(c) #max66
A variation of the HolyBlackCat's solution.
template <typename ...>
struct has_adjacent_same_types : public std::false_type
{ };
template <typename T0, typename ... Ts>
struct has_adjacent_same_types<T0, T0, Ts...> : public std::true_type
{ };
template <typename T0, typename T1, typename ... Ts>
struct has_adjacent_same_types<T0, T1, Ts...>
: public has_adjacent_same_types<T1, Ts...>
{ };
Two simpler specializations instead of only one, more complex.
Substantially is the same things (I suppose) but I find it a little clear to read and understand.
I propose also a completely different solution that uses template folding (so only C++17 or newer, unfortunately) instead of template recursion.
template <typename...>
struct sae_helper;
template <typename ... Ts, typename ... Us>
struct sae_helper<std::tuple<Ts...>, std::tuple<Us...>>
: public std::bool_constant<(std::is_same_v<Ts, Us> || ...)>
{ };
template <typename ... Ts>
struct some_adjacent_equal
: public sae_helper<std::tuple<void, Ts...>, std::tuple<Ts..., void>>
{ };
If void is a possible type in the list of type to check, calling sae_helper from some_adjacent_equal instead of void must be used a different type, obviously.
I suppose that this solution is preferable, over a recursive one, when the list of types is very long because avoid compilers template-recursion limits.
If you can use C++14, you can use a constexpr function instead of template folding (and a tag-type instead of void) as follows
template <typename ... Ts, typename ... Us>
constexpr bool sae_helper (std::tuple<Ts...> const &,
std::tuple<Us...> const &)
{
using unused = bool[];
bool ret { false };
(void)unused { true, ret |= std::is_same<Ts, Us>::value... };
return ret;
}
struct no_type
{ };
template <typename ... Ts>
struct some_adjacent_equal
: public std::integral_constant<bool, sae_helper(std::tuple<no_type, Ts...>{},
std::tuple<Ts..., no_type>{})>
{ };
but, this way, you loose short-circuiting in or evaluation.
I have a variadic template class that defines collection of types
template <typename ... Types> class TypePack { };
Which is instantiated several times
typedef TypePack<T1, T2, T3> Pack1;
typedef TypePack<T1, T2, T4> Pack2;
I want to reference TypePack parameters from other templates
template <typename Pack> Client {
static constexpr std::array<Foo, sizeof...(Pack::Types)> foos {
make_foo<Pack::Types>()...
};
};
typedef Client<Pack1> Client1;
typedef Client<Pack2> Client2;
The code above is clearly wrong and doesn't compile. It just serves as illustration of what I would like to achieve.
I could define Pack1 and Pack2 through macros but I have a feeling that it should be possible to do it with variadic templates in C++14
What you're looking for is partial specialization:
template <typename Pack> struct Client;
template <class... Ts>
struct Client<TypePack<Ts...>>
{
static constexpr std::array<Foo, sizeof...(Ts)> foos {{
make_foo<Ts>()...
}};
};
// don't forget the definition
template <class... Ts>
constexpr std::array<Foo, sizeof...(Ts)> Client<TypePack<Ts...>>::foos;
For a single function it is possible to extract its parameter types like this:
template <class T>
struct Foo;
template <class Ret, class... Args>
struct Foo<Ret(*)(Args...)> { /* stuff */ };
Would it be possible to do the same for a series of function pointers? That is,
to be able to extract the arguments and then redeploy them in the same way? E.g. something like:
template <class.. T>
struct Foo;
template <class... Rets, class... Args>
struct Foo<Rets(*)(Args...)...> // I wish this worked
{
std::tuple<Rets(*)(Args...)...> fns; // Ditto
}
Late to the party, but this might be useful. First let's define some utilities:
template <class... T>
using void_t = void;
template <bool...> struct bool_pack;
template <bool... v>
using all_true = std::is_same<bool_pack<true, v...>, bool_pack<v..., true>>;
Then a metafunction to check whether a type is a function pointer:
template <class F>
struct is_function_pointer : std::integral_constant<bool, false> { };
template <class Ret, class... Args>
struct is_function_pointer<Ret (*)(Args...)> : std::integral_constant<bool, true> { };
Using these, let's write the class. The SFINAE toggle is placed first because the variadic pack takes up the right side:
template <class = void_t<>, class... T>
struct Foo_impl;
template <class... FuncPtrs>
struct Foo_impl<
std::enable_if_t<all_true<is_function_pointer<FuncPtrs>{}...>{}>,
FuncPtrs...
> {
std::tuple<FuncPtrs...> fns;
};
Finally, a typedef to hide the SFINAE toggle from the user:
template <class... T>
using Foo = Foo_impl<void_t<>, T...>;
VoilĂ ! Foo<void (*)(), int (*)(double)> goes to the specialization of Foo_impl which contains the adequate tuple, Foo<int, double> goes to the main template.
See it live on Coliru
I have traits classes sprinkled about my code which follow the same basic idiom:
template<class Frame, typename = void>
struct frame_traits
{
typedef void base_frame_type;
};
template<class Frame>
struct frame_traits<Frame, typename std::void_t<
typename Frame::base_frame_type>::type>
{
typedef typename Frame::base_frame_type base_frame_type;
};
and I have a bunch of trait checkers which use them, which also follow a similar idiom:
template <typename T>
struct has_base_frame_type : std::integral_constant<bool,
!std::is_same<typename frame_traits<T>::base_frame_type, void>::value>::type {};
however, it turns out that has_base_frame_type has become useful to multiple concepts in my code, and I'd like to generalize it further so that I can pass the traits class as an additional parameter:
template <typename T, template<typename> class Traits = frame_traits>
struct has_base_frame_type : std::integral_constant<bool,
!std::is_same<typename Traits<T>::base_frame_type, void>::value>::type {};
This doesn't work though, since templates with default arguments cannot be used as template template parameters.
I know I could work around the problem if I always use a traits class in the template instantiation (and modify the trait checker to accept it), namely
has_base_frame_type<frame_traits<MyClass>>::value
but I don't want to do that, because it would be all too easy to forget and pass in a non-trait class. In fact, that's how I originally had the code written until I forgot the trait one too many times and refactored it.
Is there someway I can modify my trait class idiom to work around the template template parameter problem?
Framework:
#include <type_traits>
template <typename...>
using void_t = void;
template <typename AlwaysVoid, template <typename...> class Operation, typename... Args>
struct detect_impl : std::false_type {};
template <template <typename...> class Operation, typename... Args>
struct detect_impl<void_t<Operation<Args...>>, Operation, Args...> : std::true_type {};
template <template <typename...> class Operation, typename... Args>
using detect = detect_impl<void, Operation, Args...>;
Detectors:
template <class Frame>
using frame_traits = typename Frame::base_frame_type;
template <class Frame>
using other_frame_traits = typename Frame::other_frame_type;
Trait with a default detector:
template <typename T, template <typename...> class Traits = frame_traits>
using has_frame_type = detect<Traits, T>;
Test:
struct A
{
using base_frame_type = void;
};
struct B
{
using other_frame_type = void;
};
int main()
{
static_assert(has_frame_type<A>{}, "!"); // default
static_assert(!has_frame_type<B>{}, "!"); // default
static_assert(!has_frame_type<A, other_frame_traits>{}, "!"); // non-default
static_assert(has_frame_type<B, other_frame_traits>{}, "!"); // non-default
}
DEMO
I was wondering if there was any solution to find if a type was a specialization of a template that takes non-type parameters without specifying every type ?
For instance, if have a class like this:
template<typename T, std::size_t R>
struct F {}
For now, I'm using a very specialized traits:
template<template<typename, std::size_t> class TT, typename T>
struct is_2 : std::false_type { };
template<template<typename, std::size_t> class TT, typename V1, std::size_t R>
struct is_2<TT, TT<V1, R>> : std::true_type { };
and used like is_2<F, T>::value. However, this is not practical since, if you add another template parameter, you have to edit your traits. Moreover, if you have several templates of this kind, you need to write a traits for each of them.
Is there any way to make something more practical ? I can use C++14. And I don't mean using a macro to reduce the code amount.
Non-type template parameters are a bit of a red headed stepchild.
There is no "any template parameter is matched, type or not".
If you can modify F, you make it more uniform by wrapping your constants in thin types. So:
template<typename T, class R>
struct F;
template<typename T, std::size_t R>
struct F<T, std::integral_constant<std::size_t, R>> {};
now meta-programs like is can be written uniformly:
template<template<class...>class Template, class T>
struct is_instantiation : std::false_type {};
template<template<class...>class Template, class... Ts>
struct is_instantiation<Template, Template<Ts...>> : std::true_type {};
matching everything.
If you have less control over F, you can either use your approach, or write metaprogram that hoists both a template and an instance of that template into something with type wrappers.
struct meta_F {
template<class T, std::size_t R>using raw_apply=F<T,R>;
template<class T, class R>using apply=raw_apply<T,R::value_type>;
};
template<class meta_Template, class... Args>
struct type_lifted_template {};
template<class T, std::size_t R>
struct type_lifted_template< meta_F, T, std::integral_constant<std::size_t, R> > {
using result = meta_F::template raw_apply<T, R>;
};
template<class T, std::size_t R>
auto type_lift_instance( F<T,R> )
-> type_lifted_template< meta_F, T, std::integral_constant<std::size_t, R> >;
Now, type_lift_instance can be specialized for multiple types, and some decltype magic could be used to extract the type_lifted_template specialization for different types.
All of this is pretty rough. You'd be best, if you are doing lots of meta programming on templates, to just have your templates take uniform type parameters, instead of messing around with this stuff.
template<class meta_F, class C>
struct meta_template_is_lifted : std::false_type {};
template<class meta_F, class...Ts>
struct meta_template_is_lifted<meta_F, type_lifted_template< meta_F, Ts... >> : std::true_type {};
template<class meta_F, class C>
struct meta_template_is : meta_template_is_lifted< meta_F, decltype(type_lift_instance( std::declval<C>() ) ) > {};
this isn't much less typing, but the metafication goes on far away from the is code (or other similar code).
I'm probably using "lift" incorrectly.
If you can modify F and there are no other restrictions you haven't mentioned, the easiest solution would be to add a unique base class:
#include <cstddef>
#include <type_traits>
struct unique_F_base {};
template<typename T, std::size_t R>
struct F : unique_F_base
{
};
template<typename T>
using is_F = std::is_base_of<unique_F_base,T>;
int main()
{
static_assert( !is_F< int >::value, "Oops" );
static_assert( is_F< F<int,42> >::value, "Oops" );
}