File template_combinations.hxx

Routines and helper types for calling a templated function with all combinations of various sets of types/values.

Copyright 2018 D.Dickinson, P.Hill

Contact: Ben Dudson, bd512@york.ac.uk

This file is part of BOUT++.

BOUT++ is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

BOUT++ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with BOUT++. If not, see http://www.gnu.org/licenses/.

Functions

template<typename item, typename theFunction>
void addItemToDeferredFunction(theFunction func, item)

Now we define routines for dealing with Sets of types We use recursion to unpack each Set such that we can form all combinations of the contained types. As we empty Sets and get individual items we change the number of arguments and hence provide several overloads with different numbers of Sets. Finally we end up with a single item this is the point at which we have a unique combination of the template types and can final invoke the DeferredFunction

Note that we define the routines from the bottom up so that we don’t have to pre-declare routines.

Note we make use of type inferenence with templates to be able to refer to the first item in a Set/pack allowing us to extract items from Sets.This is the lowest level routine we now have a unique combination of template parameters provided to the DeferredFunction (completed by passing in item) and can therefore invoke this functor.

template<typename item, typename lastSet, typename theFunction>
void addItemToDeferredFunction(theFunction func, item, lastSet)

One Set left to process so no template pack required.

template<typename item, typename nextSet, typename ...otherSets, typename theFunction>
void addItemToDeferredFunction(theFunction func, item, nextSet, otherSets...)

More than one Set left to process.

template<typename ...Sets, typename theFunction>
void processSet(theFunction func, Set<>, Sets...)

Terminal routine the current Set is empty so nothing left to do.

template<typename firstItem, typename ...otherItems, typename ...otherSets, typename theFunction>
void processSet(theFunction func, Set<firstItem, otherItems...>, otherSets... others)

Here we use type inference to allow us to refer to the firstItem in the first Set and the otherItems in this Set. We use this to pass the firstItem off to the routines that will add this to the DeferredFunction. Following this we use recursion to call this routine again to process the rest of this Set.

template<typename ...Ts>
struct Set
#include <template_combinations.hxx>

Here we define an empty templated struct that can represent a collection of arbitrary types. This is useful for passing template packs (typename…) around whilst being able to distinguish between different template packs.

template<typename T>
struct TypeContainer
#include <template_combinations.hxx>

Here we provide a container type that can be used to pass around a type without needing to create instances of the specific type (instead we create instances of the container type).

Public Types

template<>
using type = T
template<typename currentFunction, typename currentType>
struct DeferredFunction
#include <template_combinations.hxx>

Define a struct (functor) that we use to build up the final collection of template values. Each time we create one of these objects we provide one more type to the templatePack. We may call the operator() method by providing all the required template parameters for whatever the storedFunc is at that point once we have built a complete templatePack we don’t need to specify any of these template parameters as they can be deduced/inferred.

Public Functions

DeferredFunction(currentFunction f)
template<typename ...templatePack>
void operator()(templatePack... args)

Public Members

currentFunction storedFunc
template<typename FirstSet, typename ...otherSets>
struct produceCombinations
#include <template_combinations.hxx>

This is the top level routine that takes the different Sets of types and triggers the construction of instances of theFunction with all the combinations of the template types defined by the Sets.

A use of this might look like: produceCombinations< Set<typeA, typeB, typeC>, Set<int, double, std::string> >(someFunctionWhichTakesTwoTemplateTypeArguments);

Note we wrap this in a struct such that by declaring a global variable of this type we trigger the creation of the combinations.

Public Functions

template<typename theFunction>
produceCombinations(theFunction func)