How to instantiate template from mpl::vector - c++

I have a mpl::vector & want to instantiate a template using the vector elements as template arguments. How is this done? Can a argument pack be used to consolidate extra mpl::vector elements?
For example:
struct A; struct B; struct C; struct D;
using args = mpl::vector<A, B, C, D>;
template<typename argA, typename argB, typename argC...>
struct derived_type;
using type_from_vector = derived_type<args>;
What is the best way to approach something like this?
Thanks.

[Full disclosure: I am Boost.Hana's developer]
I know this question is about Boost.MPL, but let me answer using the Boost.Hana
library (which is still in development). If you are using a recent Clang, you
might want to give this library a try; it can do everything Boost.MPL can
do, but it tries very hard to make it less painful. Here you go:
#include <boost/hana/type_list.hpp>
#include <boost/hana/type.hpp>
#include <type_traits>
namespace hana = boost::hana;
struct A; struct B; struct C; struct D;
constexpr auto args = hana::type_list<A, B, C, D>;
template<typename argA, typename argB, typename ...argC>
struct derived_type;
using type_from_vector = decltype(
hana::unpack(args, hana::template_<derived_type>)
)::type;
static_assert(std::is_same<
type_from_vector,
derived_type<A, B, C, D>
>{}, "");

You could either use boost::mpl::fold or std::make_index_sequence.
Both these code snippets assume using namespace boost::mpl;.
Using boost::mpl::fold:
template <typename TList, typename T> struct ExtendTList;
template<typename T, typename... Ts>
struct ExtendTList<derived_type<Ts...>, T>
{
using type = derived_type<Ts..., T>;
};
using type_from_vector = fold<args, derived_type<>, ExtendTList<_1, _2>>::type;
Using std::make_index_sequence:
template <typename V, template<typename...> T, typename Seq>
struct MakeFromTypesAtIndices;
template <typename V, template<typename...> T, size_t ... Indices>
struct MakeFromTypesAtIndices<V, T, std::integer_sequence<size_t, Indices...>>
{
using type = T< at<V, Indices>... >;
};
using type_from_vector = MakeFromTypesAtIndices<args, derived_type, std::make_index_sequence<size<args>::value>>::type;

Related

Expand template type

Is there a way to convert each type of std::tuple into specific subtypes?
I have following code
struct Foo1
{
struct A{};
struct B{};
};
struct Foo2
{
struct A{};
struct B{};
};
using myTypes = std::tuple<Foo1, Foo2>;
Is there a way to convert myTypes into following type?
std::tuple<Foo1::A, Foo1::B, Foo2::A, Foo2::B>;
Order of types doesn't matter, but would be nice to have it like above.
If A/B name are fixed, you might do
template <typename... Ts>
using AB_Types = std::tuple<typename Ts::A..., typename Ts::B...>;
So AB_Types<Foo1, Foo2> is std::tuple<Foo1::A, Foo2::A, Foo1::B, Foo2::B>.
Having expected order would also be possible:
template <typename... Ts>
using AB_Types_ordered =
decltype(std::tuple_cat(std::tuple<typename Ts::A, typename Ts::B>{}...));
and if source is a tuple, just add extra layer
template <typename>
struct AB_impl;
template <typename... Ts>
struct AB_impl<std::tuple<Ts...>>
{
using type = AB_Types<Ts...>; // AB_Types_ordered<Ts...>
};
template <typename T>
using AB_Types_from_tuple = typename AB_impl<T>::type;
An alternative solution based on the Boost.Mp11 library:
template<class T>
using add_AB = std::tuple<typename T::A, typename T::B>;
template <typename Tuple>
using AB_Types_from_tuple =
boost::mp11::mp_flatten<boost::mp11::mp_transform<add_AB, Tuple>>;
static_assert(std::is_same_v<
AB_Types_from_tuple<myTypes>,
std::tuple<Foo1::A, Foo1::B, Foo2::A, Foo2::B>
>);

Parameterize of tuple with repeated type

I want to declare template:
template <size_t N, class Type> my_tuple
{
using type = ... //something here
};
So that this my_typle<3, std::string>::type,for example, will be the same as this std::tuple<std::string, std::string, std::string>
Please, show, how it can be done in one line, maybe, using std::index_sequence or something from boost or whatever? Or maybe it can not be done just simple?
UPD
Please, note I do not need an std::array, I need to parametrize some variable template with predefined list of types. I have used std::tuple as an example here.
This is fun. Here's a "pure" meta-programming approach to expand the sequence:
template<typename T, typename Seq>
struct expander;
template<typename T, std::size_t... Is>
struct expander<T, std::index_sequence<Is...>> {
template<typename E, std::size_t>
using elem = E;
using type = std::tuple<elem<T, Is>...>;
};
template <size_t N, class Type>
struct my_tuple
{
using type = typename expander<Type, std::make_index_sequence<N>>::type;
};
I say "pure" ironically. It's more akin to the classic meta-programming tricks, nothing else.
Use decltype with return type of function returning tuple<string,string,...repeated N times>:
template<typename T, size_t ... Indices>
auto GetType(std::index_sequence<Indices...>) {
return std::make_tuple( (Indices,T{})... );
}
template <size_t N, class Type> class my_tuple
{
using type = decltype(GetType<Type>(std::make_index_sequence<N>())); //something here
};
template<class T>
struct Dummy;
int main(){
Dummy<my_tuple<3,std::string>::type> d;
error on d gives you tuple<string,string,string>, so it is your desired type.
You can
template <typename...>
struct cat_tuple_type;
template <typename... T1, typename... T2>
struct cat_tuple_type<std::tuple<T1...>, std::tuple<T2...>>
{
using type = std::tuple<T1..., T2...>;
};
template <size_t N, class Type> struct my_tuple
{
static_assert(N>0);
using type = typename cat_tuple_type<std::tuple<Type>, typename my_tuple<N-1, Type>::type>::type;
};
template <class Type> struct my_tuple <1, Type>
{
using type = std::tuple<Type>;
};
Then my_typle<3, std::string>::type gives the type std::tuple<std::string, std::string, std::string>.

Partial template deduction in template argument list

I have the following structs:
template<typename T1, typename T2>
struct A {};
template<typename T>
struct B {};
template<typename A, typename B>
struct C {};
and want to use them as follows:
C<B<int>, A<double, B<int>>> c;
Is there any way to deduce the second template parameter for A, such that I can use it like this?
C<B<int>, A<double>> c;
This should work for any template arguments of C and not just for a particular one (therefore default arguments don't seem to work).
Furthermore a solution for variadic templates would be even better, so instead of
C<B<int>, A<double, B<int>>, A<float, A<double, B<int>>>> c;
something like this would be nice:
C<B<int>, A<double>, A<float>> c;
With a bit of template metaprogramming fun, I was able to solve your problem both for the two-parameter and the variadic case (although in a somewhat narrow way):
// TypeList stuff
template<class... Args>
struct List {
template<class Arg>
using Add = List<Args..., Arg>;
};
template<class List> struct TailI;
template<class A, class... Ar> struct TailI<List<A, Ar...>> {
using type = typename TailI<List<Ar...>>::type;
};
template<class A> struct TailI<List<A>> {
using type = A;
};
template<class List>
using Tail = typename TailI<List>::type;
template<template<class...> class OP, class List> struct rename_impl;
template<template<class...> class OP, class... ListArgs>
struct rename_impl<OP, List<ListArgs...>> {
using type = OP<ListArgs...>;
};
template<template<class...> class OP, class List>
using rename = typename rename_impl<OP, List>::type;
// Actual code solving problem at hand
template<class T1, class T2> struct A{};
template<class... Args> struct C{};
template<class Built, class Next, class... Rest>
struct builder {
using NewBuilt = typename Built::template Add<A<Next, Tail<Built>>>;
using type = typename builder<NewBuilt, Rest...>::type;
};
template<class Built, class Next>
struct builder<Built, Next> {
using NewBuilt = typename Built::template Add<A<Next, Tail<Built>>>;
using type = rename<C, NewBuilt>;
};
template<class First, class... Rest>
using c_builder = typename builder<List<First>, Rest...>::type;
using t = c_builder<int, double, float>;
// Test driver
#include <utility>
static_assert(std::is_same_v<t, C<int, A<double, int>, A<float, A<double, int>>>>, "");
For the simpler case of
template<typename A, typename B> struct C {};
you can use a helper class to provide you the type you need.
template<typename T1, typename T2>
struct C_Helper
{
using type = C<B<T1>, A<T2, B<T1>>>;
};
and use
using C_Type = typename C_Helper<int, double>::type;
C_Type c;
I haven't thought through how that can be extended to support a variadic class template C,

Accessing template arguments from specialization

template<typename T, typename U>
struct A;
template<std::size_t I>
struct A<int, char[I]> {
using pointer = T*; // does not compile
};
int main() {
A<int, char[3]> a;
}
Is there any way to access the type T (= int) from inside the class template specialization A<int, char[I]>, without explicitly writing the type that is has in the specialization?
Something like this:
template<class T, class U, class=T, class=U>
struct A;
template<std::size_t I, class T, class U>
struct A<int, char[I], T, U> {
using pointer = T*;
};
works. If someone actually passes a type for the second T and U problems develop, but...
Another approach is:
template<class T, class U>
struct A;
// get args from an instance!
template<class A>
struct A_Args;
template<class T_, class U_>
struct A_Args<A<T_,U_>> {
using T = T_; using U = U_;
};
template<class A>
using A_T = typename A_Args<A>::T;
template<class A>
using A_U = typename A_Args<A>::U;
// reflect on our troubles:
template<std::size_t I>
struct A<int, char[I]> {
using pointer = A_T<A>*;
};
where we have a using alias that extracts args from a generic A which we use within the specialization.
This version can be made generic with an interface like:
template<std::size_t I, class Instance>
struct nth_template_arg;
template<std::size_t I, class Instance>
using nth_template_arg_t=typename nth_template_arg<I, Instance>::type;
with the note it will only work with templates that only take type arguments. (implementation left as an exercise. I'd probably use tuple_element for a first pass; using tuples has the downside that they are heavy types, and metaprogramming with heavy types sucks performance and sometimes causes other problems.)
Simply,
#include <type_traits>
template<class T, class U>
struct foo;
template<class T, std::size_t Index>
struct foo<T, char[Index]>
{
using type = T;
};
int
main()
{
static_assert(std::is_same<foo<int, char[3]>::type, int>::value, "");
}
You can try this:
template<typename T, typename U, std::size_t I>
struct A{
using pointer = T*;
};

Ignoring duplicate explicit instantiations of template classes in C++

If I have a class:
template <typename T>
class MyClass
{
// ...
};
and I explicitly instantiate it:
template class MyClass<int>;
template class MyClass<int>; // second time
I get an error on some compilers (Clang for example, but not on VC++ 2010). Why would I want to do this? Well, in some cases T may be a typedef to another type.
template class MyClass<my_type_1>;
template class MyClass<my_type_2>;
With certain build options, my_type_1 is the same as my_type_2 and in other cases it is different. How would I make sure that the above compiles in all scenarios? Is there a way to ignore the duplicate instantiation?
You could find another way to explicitly instantiate the template in a way that you can do metaprogramming on it.
Then instead of doing one instantiation per line, do them all in a pack. Run an n^2 algorithm on them (at compile time) to eliminate duplicates (or, honestly, you could probably skip that: depending on how you instantiate the template, it might not care).
Something like this, assuming Instantiate< Template, types< blah, foo, bar > > actually instantiates the list on the template passed in as the first argument:
#include <utility>
#include <type_traits>
template<typename T>
struct Test {};
template<typename... Ts>
struct types {};
template<template<typename>class Template, typename Types>
struct Instantiate {};
template<template<typename>class Template, typename T0, typename... Ts>
struct Instantiate<Template, types<T0, Ts...>>:
Instantiate<Template, types<Ts...>>
{
Template<T0>& unused();
};
template<typename U, typename Types>
struct prepend;
template<typename U, template<typename...>class pack, typename... Ts>
struct prepend< U, pack<Ts...> > {
typedef pack<U, Ts...> types;
};
template<typename U, typename Types>
using Prepend = typename prepend<U, Types>::types;
template<typename U, typename Types, typename=void>
struct remove_type_from_types;
template<typename U, template<typename...>class pack>
struct remove_type_from_types<U, pack<>, void>
{
typedef pack<> types;
};
template<typename U, template<typename...>class pack, typename T0, typename... Ts>
struct remove_type_from_types< U, pack<T0, Ts...>,
typename std::enable_if< std::is_same<U, T0>::value >::type
>: remove_type_from_types< U, pack<Ts...> >
{};
template<typename U, template<typename...>class pack, typename T0, typename... Ts>
struct remove_type_from_types< U, pack<T0, Ts...>,
typename std::enable_if< !std::is_same<U, T0>::value >::type
>
{
typedef Prepend< T0, typename remove_type_from_types< U, pack<Ts...> >::types > types;
};
template<typename Types>
struct remove_duplicates {
typedef Types types;
};
template<template<typename...>class pack, typename T0, typename... Ts>
struct remove_duplicates<pack<T0, Ts...>> {
private:
typedef typename remove_type_from_types< T0, pack<Ts...> >::types filtered_tail;
typedef typename remove_duplicates< filtered_tail >::types unique_tail;
public:
typedef Prepend< T0, unique_tail > types;
};
template<typename Types>
using RemoveDuplicates = typename remove_duplicates<Types>::types;
static Instantiate<Test, RemoveDuplicates<types<int, double>> > unused;
int main() {
}
As noted, you can probably do away with the entire eliminate-duplicates bit, because of how I'm instantiating the use of the template. I am also not sure if the above use of each template is sufficient to instantiate it (ie, that it won't be optimized away somehow, and that the symbol will be exported).
(Recursion depth is n in the number of types, and total work done is n^2 in the number of types: that is shallow enough and fast enough for any reasonable number of types, I suspect. Fancier unique type removal is difficult, due to lack of weak ordering on naked types...)
Don't specialize for the typedefs, instead specialize for the relevant underlying types (such as int). That way you can typedef as many/few times as you like and you still always get the specializations you want.
You can define a preprocessor flag for you configuration and then put template inside an #ifdef block.
Yakk saved my days. Actually I have lots of non-type template functions with parameters calculated at compile time depend on some "#define"s. I won't know in advance their values and I want to instantiate them explicitly. But when they are conflicting, the compiler stops with the error "duplicate ...". So I followed the idea of Yakk and I made a very simple version of his. I post it here for someones possibly interested.
File 1: instantiate.h
#ifndef INC_INSTANTIATE_H
#define INC_INSTANTIATE_H
#include <iostream>
#include <utility>
#include <type_traits>
using namespace std;
template<unsigned short base> void func();
template<unsigned short base>
struct test {
test() {
cout << "Class " << base << " instantiated.\n";
func<base>();
}
void instantiate_me(){};
};
template<typename... Ts>
struct instances {};
template<typename Types>
struct Instantiate {};
template<typename T0, typename... Ts>
struct Instantiate<instances<T0, Ts...>> : Instantiate<instances<Ts...>>
{
T0 unused;
};
#endif
File 2: instantiate.cpp
#include <iostream>
#include "instantiate.h"
using namespace std;
static Instantiate<instances<test<1>, test<2>, test<3>, test<4>>> unused;
template<unsigned short base>
void func() {
cout << "Function " << base << " instantiated.\n";
}
static int initialize() {
unused.unused.instantiate_me();
return 0;
}
static int dummy = initialize();
File 3: main.cpp
#include <iostream>
#include "instantiate.h"
using namespace std;
int main() {
cout << "Good day commander!\n";
}
It works perfectly with g++ 8.0.1 ubuntu 18.04 hyper-v windows 10. Here I do not
need to care about template duplication because I explicitly use implicit instantiation, in one file there won't never be duplication. With all functions' definitions in one file, I can instantiate it in the constructor
of the class "test" in the file instantiate.h. With plural files, I use one Instantiate, one initialize and one dummy for each, with possibly plural implementations of the class "test".
using the extern template syntax can solve the problem, example:
extern template int max (int, int);