Determining largest sizeof() in boost variant - c++

Given:
boost::variant<T1,T2,T3,...,TN>
Calculate the following at compile time:
max(sizeof(T1), sizeof(T2), sizeof(T3),... ,sizeof(TN))
I had no idea how to approach this, but this answer shed some light on how I might get started. Using the code in that answer with two types, T1 and T2, I could use the following in a source file to get the size of the larger object:
size_t largestSize = sizeof(largest<T1, T2>::type);
This is exactly what I'd like to do, but I need the largest template to work with more than two classes - specifically, it would need to check all types stored in a boost::variant object.
I know that boost::variant has a types typedef, which defines some sort of list of types in the variant. The problem is, I get totally lost when I try to wrap my head around all the boost::mpl stuff in the implementation. I don't intuitively understand what boost::variant::types is, and how I might be able to pass it into my own template that does something with it.
In my head, this is what the final implementation might look like:
typedef boost::variant<T1, T2, T3, T4> MyVariant;
size_t largestSize = sizeof(largest<MyVariant::types>::type);
Unfortunately, I have no idea how to go about implementing this version of largest.
I'm not sure if this is a reasonable approach, so I'm open to any other ways to accomplish this (maybe apply a boost::static_visitor to all types at compile time?).

Just ignore the mpl stuff. Start with:
template <class T> struct max_variant_sizeof;
template <class... Ts>
struct max_variant_sizeof<boost::variant<Ts...>> {
static constexpr size_t value = variadic_max(sizeof(Ts)...);
};
Now max_variant_sizeof<MyVariant>::value will forward all the sizes of all the types to a function. All you need to do is write that variadic_max:
constexpr size_t variadic_max(size_t v) { return v; }
template <class... Args>
constexpr size_t variadic_max(size_t a, size_t b, Args... cs)
{
return variadic_max(std::max(a, b), cs...);
}
Before C++14, std::max() isn't constexpr, so that can be replaced with:
return variadic_max((a > b ? a : b), cs...);
One thing worth noting about:
maybe apply a boost::static_visitor to all types at compile time?
Visitation with a variant is a runtime operation - your visitor gets called with the type that the variant happens to be holding on to. It will not be called with all the types.

You could also change the code from the link you attached to:
template <class First, class... Args>
struct largest: largest<First, typename largest<Args...>::type> {
};
template<bool, typename T1, typename T2>
struct is_cond {
typedef T1 type;
};
template<typename T1, typename T2>
struct is_cond<false, T1, T2> {
typedef T2 type;
};
template<typename T1, typename T2>
struct largest<T1, T2> {
typedef typename is_cond< (sizeof(T1)>sizeof(T2)), T1, T2>::type type;
};
Then the usage could look like:
cout << sizeof(largest<int, char, double>::type) << endl;
Edit:
To make it work with boost::variant as well as any other variadic args templated class just add another specialization:
template <template <class...> class Var, class... Args>
struct largest<Var<Args...>>: largest<Args...> { };
Then usage could look e.g. (with tuple, that can be successfully changed to boost::variant):
cout << sizeof(largest<tuple<int, char, double>>::type) << endl;

I have using the boost::mpl library as a generic library for compile time code operations.
Some header code preparation:
#include <boost/mpl/vector.hpp>
#include <boost/mpl/max_element.hpp>
#include <boost/mpl/transform_view.hpp>
#include <boost/mpl/sizeof.hpp>
#include <boost/type_traits/alignment_of.hpp>
// alignof_ headers
#include <boost/mpl/size_t.hpp>
#include <boost/mpl/aux_/na_spec.hpp>
#include <boost/mpl/aux_/lambda_support.hpp>
// alignof mpl style implementation (namespace injection) the same way as the `mpl::sizeof_` did
namespace boost {
namespace mpl {
template<
typename BOOST_MPL_AUX_NA_PARAM(T)
>
struct alignof_
: mpl::size_t< boost::alignment_of<T>::value >
{
BOOST_MPL_AUX_LAMBDA_SUPPORT(1, alignof_, (T))
};
BOOST_MPL_AUX_NA_SPEC_NO_ETI(1, alignof_)
}
}
'
Some helper macro:
// generates compilation error and shows real type name (and place of declaration in some cases) in an error message, useful for debugging boost::mpl recurrent types
// old C++ standard compatible
//#define UTILITY_TYPE_LOOKUP_BY_ERROR(type_name) \
// (*(::utility::type_lookup<type_name >::type*)0).operator ,(*(::utility::dummy*)0)
// can be applied in a class, but requires `decltype` support
#define UTILITY_TYPE_LOOKUP_BY_ERROR(type_name) \
typedef decltype((*(::utility::type_lookup<type_name >::type*)0).operator ,(*(::utility::dummy*)0)) _type_lookup_t
namespace utility
{
struct dummy {};
template <typename T>
struct type_lookup
{
typedef T type;
};
}
'
Usage example:
namespace mpl = bost::mpl;
typedef mpl::vector<T1, T2, T3, T4, T5> storage_types_t;
typedef typename mpl::deref<
typename mpl::max_element<
mpl::transform_view<storage_types_t, mpl::sizeof_<mpl::_1> >
>::type
>::type max_size_t; // type has stored max sizeof(T1, T2, T3, T4, T5)
typedef typename mpl::deref<
typename mpl::max_element<
mpl::transform_view<storage_types_t, mpl::alignof_<mpl::_1> >
>::type
>::type max_alignment_t; // type has stored max alignof(T1, T2, T3, T4, T5)
// testing on real values
UTILITY_TYPE_LOOKUP_BY_ERROR(max_size_t);
UTILITY_TYPE_LOOKUP_BY_ERROR(max_alignment_t);
'
Visual Studio 2015 error output:
error C2039: ',': is not a member of 'boost::mpl::size_t<**calculated max sizeof here**>'
error C2039: ',': is not a member of 'boost::mpl::size_t<**calculated max alignment here**>'

Related

C++ Template Meta Programming: Inheritance from template template parameter

#include <type_traits>
template <typename T1, typename T2, typename is_allocated>
struct mutable_storage {};
template <
template<typename, typename, typename> class storage_t,
typename T2 = void,
typename is_allocated = std::false_type
>
class Buffer : storage_t<Buffer<storage_t,void,void>, T2, is_allocated>
{};
int main() {
typedef Buffer<mutable_storage> example_buffer;
}
This code compiles (at least using the GNU GCC Compiler following C++14). However, I dislike the used syntax
class Buffer : storage_t<Buffer<storage_t,void,void>, T2, is_allocated>
due to the fact it shouldn't require the Buffer to be specialized: I would like Buffer to be recognized as a template template parameter, like:
class Buffer : storage_t<Buffer, T2, is_allocated>
Then I would like the mutable_storage struct to recognize a template specialization like
template <typename T2, typename is_allocated>
struct mutable_storage<Buffer, T2, is_allocated> { ... };
(Would of course not be allowed, as "Buffer" is not a type, so that should be changed too).
But the way it uses right now, being able to specialize with type
Buffer feels a bit nasty. Using a typedef, for example
typedef Buffer<storage_t, void, void> Buffer_Policy
also feels a bit nasty. I'm looking for a cleaner way. I've tried to make a template template template parameter, but that leads to an infinite flow of extra templates within the template parameter (I don't know exactly how template<...> works, so maybe that?), as the Buffer inherits from something that requires another Buffer in order to declare storage_t. I've also tried using a implicit class, namely inner_storage_t. Neither did this lead to a success. Does anyone have suggestions in order to make the program cleaner? By the way, if you see any other mistakes or inefficiencies, feel free to mention it. Thanks for reading and possibly your help.
Since T1 is only meant to be used for template specialization selection, you don't really have to use Buffer itself. You can use a tag type instead.
Squirreling it away in a namespace also allows you to avoid polluting the rest of the enclosing namespace with the tags.
#include <type_traits>
template <typename T1, typename T2, typename is_allocated>
struct mutable_storage {};
namespace storage_tags {
struct Buffer_T {};
}
template <
template<typename, typename, typename> class storage_t,
typename T2 = void,
typename is_allocated = std::false_type
>
class Buffer : public storage_t<storage_tags::Buffer_T, T2, is_allocated> {
};

Lowest common ancestor in a linear lineage of types

Intro
Let's suppose that we have a linear hierarchy of types like the following:
Then what I want is a mechanism to return the lowest common ancestor out of an arbitrary number of types in that lineage.
Attempted Code
template<typename...Ts>
struct LCA;
template<typename T1, typename T2, typename...Ts>
struct LCA<T1, T2, Ts...>
{
using base = typename std::conditional
<
std::is_base_of<T1, T2>::value, T1,
typename std::conditional <
std::is_base_of<T2, T1>::value, T2, void
>::type
>::type;
using type = typename LCA<base, Ts...>::type;
};
template<typename T>
struct LCA<T>
{
using type = T;
};
Live Demo
Use Case
My use case is rather typical: In making some iterator tools I want to extract the "most restrictive" iterator type, so since there's (kind of) a linear hierarchy in iterators I should to able to ascent the hierarchy as much as it's needed:
LCA<Bidirectional, RandomAccess, RandomAccess> -> Bidirectional
LCA<RandomAccess, Input, Forward> -> Input
Questions
Is there a more concise / idiomatic way of handling of the error case where two or more types are strangers to the hierarchy? The current approach is to return void which hopefully will give failure in most contexts where the type is actually used.
Is the use of an extra base member in the first specialization problematic? Should I extract that functionality in a separate class and use it inline in type to maintain uniformity?
Is there an algorithm that would reduce the number of instantiations? Is there a better way than pairwise comparisons, so that the complexity of the algorithm can be reduced?
Can anyone scale to non linear hierarchies and query by depth a hierarchy tree? What would be a good "tie breaker" in that case (for types in the same level)?
1. Technical aspect
I'd use derivation, because this is cleaner than type definitions. Here is some example code:
#include <iostream>
#include <typeinfo>
#include <type_traits>
struct Grandma {};
struct Mom : Grandma {};
struct Daughter : Mom {};
struct Son : Mom {};
struct Grandchild : Son {};
struct Stranger {};
namespace detail
{
struct TypeIsNotPartOfTheHierarchy {};
template<typename T>
struct TypeWrapper
{
static_assert(!std::is_same<TypeIsNotPartOfTheHierarchy, T>::value,
"using types of different type hierarchies.");
using type = T;
};
}
template<typename... Ts>
struct LCA;
template<typename T>
struct LCA<T>: detail::TypeWrapper<T>
{};
template<typename T1, typename T2>
struct LCA<T1, T2>:
std::conditional
<
std::is_base_of<T1, T2>::value,
detail::TypeWrapper<T1>,
typename std::conditional
<
std::is_base_of<T2, T1>::value,
detail::TypeWrapper<T2>,
detail::TypeWrapper<detail::TypeIsNotPartOfTheHierarchy>
>::type
>::type
{};
template<typename T1, typename... Ts>
struct LCA<T1, Ts...>: LCA<T1, typename LCA<Ts...>::type>
{};
int main()
{
std::cout << typeid(LCA<Son, Mom, Grandchild, Grandma, Son, Son>::type).name() << std::endl;
std::cout << typeid(LCA<Son>::type).name() << std::endl;
// error because Daughter and Son are siblings.
// std::cout << typeid(LCA<Son, Daughter, Son>::type).name() << std::endl;
// error because Son is not related to the Stranger.
// std::cout << typeid(LCA<Son, Stranger, Son>::type).name() << std::endl;
return 0;
}
Technically you could use std::enable_if instead of std::condition, but using std::enable_if would mean, that you have to derive from the if-true, if-false and if-types-not-compatible case. Using std::condition is IMHO more readable. The type has to be wrapped once more to have a type, that could be enabled by the conditions and then deliver a typedef for using it outside.
In order get a compilation error, statically asserting it would give you a nice message instead of difficult template errors in the compiler output. Then you are free to use the void to signalize an error. I would recommend to use an extra type to name this error. This also improves readability.
2. Base type
I think the base member should be hidden, because else you reveal more than needed to the users and this may confuse them. The use of type derivation solves this issue.
3. Complexity
I think, that it is not possible to improve the complexity O(n). You have to check each type at least once, if it could be the LCA type. So every type is at least once part of a comparison.
4. Other hierarchies (the beautiful part)
The implementation above (as yours too) makes no point on other hierarchies than linear ones (e.g. LCA<Daughter, Grandma, Son> will return Grandma while LCA<Grandma, Daughter, Son>::type will result in an error, because only the neighbour types are compared).
However there are two types of "branching inheritance" in C++ possible (and mixing it of course):
Tree with multiple roots:
struct Dad {};
struct Mom {};
struct Son: Dad, Mom {};
For several cases the LCA is undefined (e.g. LCA<Mom, Dad>::type I guess, that Mom and Dad do not share the same parents). So I would recommend to drop this case.
Tree with one root:
struct Mom {};
struct Son: Mom {};
struct Daughter: Mom {};
I would recommend, that the algorithm returns only a type, if there is one type in the list, to which all types could be casted into (e.g. LCA<Son, Daughter>::type has no LCA, because I hope that they are siblings). So we search that type in the list that is a base type of all others.
Because only neighbour types are compared to each other above, the comparison has to be extended to compare every type with each other (sadly this is O(n^2)). So the basic idea is to check for every type, if it is a common ancestor for all other types. This is only the case for the LCA. BTW: Solving it that way has another advantage, because you will get an error in a "multiple roots"-scenario, but the correct result, if the multiple roots are joining again in a common root (that is part of the list).
We need first of all a functionality, that determines whether one type is a base type of all other or not:
template<typename StillCommonAncestor, typename TypeToCheck, typename... Ts>
struct IsCommonAncestor;
template<typename StillCommonAncestor, typename TypeToCheck>
struct IsCommonAncestor<StillCommonAncestor, TypeToCheck>
{
static constexpr bool value = StillCommonAncestor::value;
};
template<typename StillCommonAncestor, typename TypeToCheck, typename T1, typename... Ts>
struct IsCommonAncestor<StillCommonAncestor, TypeToCheck, T1, Ts...>:
IsCommonAncestor
<
std::integral_constant
<
bool,
std::conditional
<
std::is_base_of<TypeToCheck, T1>::value,
std::true_type,
std::false_type
>::type::value && StillCommonAncestor::value
>,
TypeToCheck,
Ts...
>
{};
To check whether a type is the common ancestor of all others, simply use IsCommonAncestor<std::true_type, Mom, Grandchild, Daughter, Son>::value (which is here true, while IsCommonAncestor<std::true_type, Grandchild, Grandchild, Daughter, Son>::value is false). Note that, the value is also false, if one type is not part of the type hierarchy.
Then some "facility" is needed, to iterate through the types and catch the only one, for which IsCommonAncestor<...>::value is true:
template<typename Pack, typename... Ts>
struct LCA;
template<typename... PackParams, typename T1>
struct LCA<std::tuple<PackParams...>, T1>:
std::conditional
<
IsCommonAncestor<std::true_type, T1, PackParams...>::value,
TypeWrapper<T1>,
TypeWrapper<TypeIsNotPartOfTheHierarchy>
>::type
{};
template<typename... PackParams, typename T1, typename... Ts>
struct LCA<std::tuple<PackParams...>, T1, Ts...>:
std::conditional
<
IsCommonAncestor<std::true_type, T1, PackParams...>::value,
TypeWrapper<T1>,
LCA<std::tuple<PackParams...>, Ts...>
>::type
{};
The LCA compares every element with the whole template parameter pack. The first
that is the base type of all is used. If the last is also no base type of all
others, LCA derives again from TypeWrapper<TypeIsNotPartOfTheHierarchy>, which
will raise the typical static assertion.
This one is very inconvenient. A wrapper will fix this:
template<typename... Ts>
struct LCA: detail::LCA<std::tuple<Ts...>, Ts...>
{};
Complete code for the LCA of a tree is available here: http://ideone.com/pYEPYl
std::enable_if results in a compilation error, if the first template parameter is false. Another alternative to falling back to defining a void type is to result in a compilation error.
I think that the template will be neater if explicit inheritance is used, as a means of resolving to the correct type, see below.
I don't see how the complexity could be reduced below linear complexity. Somehow, in some way, you have to iterate over all the template parameter types, in order to select one of them.
std::is_base_of doesn't really give you an indication of how deep the subclass goes below the superclass, just that one is a subclass of the other. Additionally, with multiple inheritance, a given subclass could occur at different levels below the superclass, so the semantics there are a bit muddy.
Anyway, I think that using a separate class to perform the pairwise type comparison, and using inheritance, looks cleaner:
template<typename T1, typename T2, bool is_t1_base, bool is_t2_base>
class which_one_is_base;
// If T1 and T2 are the same, dontcare will be true.
template<typename T1, typename T2, bool dontcare>
class which_one_is_base<T1, T2, true, dontcare> {
public:
typedef T1 type;
};
template<typename T1, typename T2>
class which_one_is_base<T1, T2, false, true> {
public:
typedef T2 type;
};
template<typename T1, typename T2>
class select_base : public which_one_is_base<T1, T2,
std::is_base_of<T1, T2>::value,
std::is_base_of<T2, T1>::value>
{
};
//////////////////////////////////////////////////////////////////////
template<typename ...Ts> class LCA;
template<typename T1> class LCA<T1> {
public:
typedef T1 type;
};
template<typename T1, typename T2, typename ...Ts>
class LCA<T1, T2, Ts...> :
public LCA< typename select_base<T1, T2>::type, Ts...> {
};

The std::transform-like function that returns transformed container

I'm trying to implement a function similar to std::transform algorithm but instead of taking the output iterator by an argument I want to create and return a container with transformed input elements.
Let's say that it's named transform_container and takes two arguments: container and functor. It should return the same container type but possibly parametrized by a different element type (the Functor can return element of different type).
I'd like to use my function as in the example below:
std::vector<int> vi{ 1, 2, 3, 4, 5 };
auto vs = transform_container(vi, [] (int i) { return std::to_string(i); });
//vs will be std::vector<std::string>
assert(vs == std::vector<std::string>({"1", "2", "3", "4", "5"}));
std::set<int> si{ 5, 10, 15 };
auto sd = transform_container(si, [] (int i) { return i / 2.; });
//sd will be of type std::set<double>
assert(sd == std::set<double>({5/2., 10/2., 15/2.}));
I was able two write two functions — one for std::set and one for std::vector — that seem to work properly. They are identical, except of the container typename. Their code is listed below.
template<typename T, typename Functor>
auto transform_container(const std::vector<T> &v, Functor &&f) -> std::vector<decltype(f(*v.begin()))>
{
std::vector<decltype(f(*v.begin()))> ret;
std::transform(std::begin(v), std::end(v), std::inserter(ret, ret.end()), f);
return ret;
}
template<typename T, typename Functor>
auto transform_container(const std::set<T> &v, Functor &&f) -> std::set<decltype(f(*v.begin()))>
{
std::set<decltype(f(*v.begin()))> ret;
std::transform(std::begin(v), std::end(v), std::inserter(ret, ret.end()), f);
return ret;
}
However, when I attempted to merge them into a single general function that works with any container, I encountered numerous issues. The set and vector are class templates, so my function template must take a template template parameter. Moreover, set and vector templates have a different number of type parameters that needs to be properly adjusted.
What is the best way to generalize the two function templates above into a function that works with any compatible container type?
Simplest cases: matching container types
For the simple case where the input type matches the output type (which I've since realized is not what you're asking about) go one level higher. Instead of specifying the type T that your container uses, and trying to specialize on a vector<T>, etc., just specify the type of the container itself:
template <typename Container, typename Functor>
Container transform_container(const Container& c, Functor &&f)
{
Container ret;
std::transform(std::begin(c), std::end(c), std::inserter(ret, std::end(ret)), f);
return ret;
}
More complexity: compatible value types
Since you want to try to change the item type stored by the container, you'll need to use a template template parameter, and modify the T to that which the returned container uses.
template <
template <typename T, typename... Ts> class Container,
typename Functor,
typename T, // <-- This is the one we'll override in the return container
typename U = std::result_of<Functor(T)>::type,
typename... Ts
>
Container<U, Ts...> transform_container(const Container<T, Ts...>& c, Functor &&f)
{
Container<U, Ts...> ret;
std::transform(std::begin(c), std::end(c), std::inserter(ret, std::end(ret)), f);
return ret;
}
What of incompatible value types?
This only gets us partway there. It works fine with a transform from signed to unsigned but, when resolving with T=int and U=std::string, and handling sets, it tries to instantiate std::set<std::string, std::less<int>, ...> and thus doesn't compile.
To fix this, we want to take an arbitrary set of parameters and replace instances of T with U, even if they are the parameters to other template parameters. Thus std::set<int, std::less<int>> should become std::set<std::string, std::less<std::string>>, and so forth. This involves some custom template meta programming, as suggested by other answers.
Template metaprogramming to the rescue
Let's create a template, name it replace_type, and have it convert T to U, and K<T> to K<U>. First let's handle the general case. If it's not a templated type, and it doesn't match T, its type shall remain K:
template <typename K, typename ...>
struct replace_type { using type = K; };
Then a specialization. If it's not a templated type, and it does match T, its type shall become U:
template <typename T, typename U>
struct replace_type<T, T, U> { using type = U; };
And finally a recursive step to handle parameters to templated types. For each type in a templated type's parameters, replace the types accordingly:
template <template <typename... Ks> class K, typename T, typename U, typename... Ks>
struct replace_type<K<Ks...>, T, U>
{
using type = K<typename replace_type<Ks, T, U>::type ...>;
};
And finally update transform_container to use replace_type:
template <
template <typename T, typename... Ts> class Container,
typename Functor,
typename T,
typename U = typename std::result_of<Functor(T)>::type,
typename... Ts,
typename Result = typename replace_type<Container<T, Ts...>, T, U>::type
>
Result transform_container(const Container<T, Ts...>& c, Functor &&f)
{
Result ret;
std::transform(std::begin(c), std::end(c), std::inserter(ret, std::end(ret)), f);
return ret;
}
Is this complete?
The problem with this approach is it is not necessarily safe. If you're converting from Container<MyCustomType> to Container<SomethingElse>, it's likely fine. But when converting from Container<builtin_type> to Container<SomethingElse> it's plausible that another template parameter shouldn't be converted from builtin_type to SomethingElse. Furthermore, alternate containers like std::map or std::array bring more problems to the party.
Handling std::map and std::unordered_map isn't too bad. The primary problem is that replace_type needs to replace more types. Not only is there a T -> U replacement, but also a std::pair<T, T2> -> std::pair<U, U2> replacement. This increases the level of concern for unwanted type replacements as there's more than a single type in flight. That said, here's what I found to work; note that in testing I needed to specify the return type of the lambda function that transformed my map's pairs:
// map-like classes are harder. You have to replace both the key and the key-value pair types
// Give a base case replacing a pair type to resolve ambiguities introduced below
template <typename T1, typename T2, typename U1, typename U2>
struct replace_type<std::pair<T1, T2>, std::pair<T1, T2>, std::pair<U1, U2>>
{
using type = std::pair<U1, U2>;
};
// Now the extended case that replaces T1->U1 and pair<T1,T2> -> pair<T2,U2>
template <template <typename...> class K, typename T1, typename T2, typename U1, typename U2, typename... Ks>
struct replace_type<K<T1, T2, Ks...>, std::pair<const T1, T2>, std::pair<const U1, U2>>
{
using type = K<U1, U2,
typename replace_type<
typename replace_type<Ks, T1, U1>::type,
std::pair<const T1, T2>,
std::pair<const U1, U2>
>::type ...
>;
};
What about std::array?
Handling std::array adds to the pain, as its template parameters cannot be deduced in the template above. As Jarod42 notes, this is due to its parameters including values instead of just types. I've gotten partway by adding specializations and introducing a helper contained_type that extracts T for me (side note, per Constructor this is better written as the much simpler typename Container::value_type and works for all types I've discussed here). Even without the std::array specializations this allows me to simplify my transform_container template to the following (this may be a win even without support for std::array):
template <typename T, size_t N, typename U>
struct replace_type<std::array<T, N>, T, U> { using type = std::array<U, N>; };
// contained_type<C>::type is T when C is vector<T, ...>, set<T, ...>, or std::array<T, N>.
// This is better written as typename C::value_type, but may be necessary for bad containers
template <typename T, typename...>
struct contained_type { };
template <template <typename ... Cs> class C, typename T, typename... Ts>
struct contained_type<C<T, Ts...>> { using type = T; };
template <typename T, size_t N>
struct contained_type<std::array<T, N>> { using type = T; };
template <
typename Container,
typename Functor,
typename T = typename contained_type<Container>::type,
typename U = typename std::result_of<Functor(T)>::type,
typename Result = typename replace_type<Container, T, U>::type
>
Result transform_container(const Container& c, Functor &&f)
{
// as above
}
However the current implementation of transform_container uses std::inserter which does not work with std::array. While it's possible to make more specializations, I'm going to leave this as a template soup exercise for an interested reader. I would personally choose to live without support for std::array in most cases.
View the cumulative live example
Full disclosure: while this approach was influenced by Ali's quoting of Kerrek SB's answer, I didn't manage to get that to work in Visual Studio 2013, so I built the above alternative myself. Many thanks to parts of Kerrek SB's original answer are still necessary, as well as to prodding and encouragement from Constructor and Jarod42.
Some remarks
The following method allows to transform containers of any type from the standard library (there is a problem with std::array, see below). The only requirement for the container is that it should use default std::allocator classes, std::less, std::equal_to and std::hash function objects. So we have 3 groups of containers from the standard library:
Containers with one non-default template type parameter (type of value):
std::vector, std::deque, std::list, std::forward_list, [std::valarray]
std::queue, std::priority_queue, std::stack
std::set, std::unordered_set
Containers with two non-default template type parameters (type of key and type of value):
std::map, std::multi_map, std::unordered_map, std::unordered_multimap
Container with two non-default parameters: type parameter (type of value) and non-type parameter (size):
std::array
Implementation
convert_container helper class convert types of known input container type (InputContainer) and output value type (OutputType) to the type of the output container(typename convert_container<InputContainer, Output>::type):
template <class InputContainer, class OutputType>
struct convert_container;
// conversion for the first group of standard containers
template <template <class...> class C, class IT, class OT>
struct convert_container<C<IT>, OT>
{
using type = C<OT>;
};
// conversion for the second group of standard containers
template <template <class...> class C, class IK, class IT, class OK, class OT>
struct convert_container<C<IK, IT>, std::pair<OK, OT>>
{
using type = C<OK, OT>;
};
// conversion for the third group of standard containers
template
<
template <class, std::size_t> class C, std::size_t N, class IT, class OT
>
struct convert_container<C<IT, N>, OT>
{
using type = C<OT, N>;
};
template <typename C, typename T>
using convert_container_t = typename convert_container<C, T>::type;
transform_container function implementation:
template
<
class InputContainer,
class Functor,
class InputType = typename InputContainer::value_type,
class OutputType = typename std::result_of<Functor(InputType)>::type,
class OutputContainer = convert_container_t<InputContainer, OutputType>
>
OutputContainer transform_container(const InputContainer& ic, Functor f)
{
OutputContainer oc;
std::transform(std::begin(ic), std::end(ic), std::inserter(oc, oc.end()), f);
return oc;
}
Example of use
See live example with the following conversions:
std::vector<int> -> std::vector<std::string>,
std::set<int> -> std::set<double>,
std::map<int, char> -> std::map<char, int>.
Problems
std::array<int, 3> -> std::array<double, 3> conversion doesn't compile because std::array haven't insert method which is needed due to std::inserter). transform_container function shouldn't also work for this reason with the following containers: std::forward_list, std::queue, std::priority_queue, std::stack, [std::valarray].
Doing this in general is going to be pretty hard.
First, consider std::vector<T, Allocator=std::allocator<T>>, and let's say your functor transforms T->U. Not only do we have to map the first type argument, but really we ought to use Allocator<T>::rebind<U> to get the second. This means we need to know the second argument is an allocator in the first place ... or we need some machinery to check it has a rebind member template and use it.
Next, consider std::array<T, N>. Here we need to know the second argument should be copied literally to our std::array<U, N>. Perhaps we can take non-type parameters without change, rebind type parameters which have a rebind member template, and replace literal T with U?
Now, std::map<Key, T, Compare=std::less<Key>, Allocator=std::allocator<std::pair<Key,T>>>. We should take Key without change, replace T with U, take Compare without change and rebind Allocator to std::allocator<std::pair<Key, U>>. That's a little more complicated.
So ... can you live without any of that flexibility? Are you happy to ignore associative containers and assume the default allocator is ok for your transformed output container?
The major difficulty is to somehow get the container type Container from Conainer<T>. I have shamelessly stolen the code from template metaprogramming: (trait for?) dissecting a specified template into types T<T2,T3 N,T4, ...>, in particular, Kerrek SB's answer (the accepted answer), as I am not familiar with template metaprogramming.
#include <algorithm>
#include <cassert>
#include <type_traits>
// stolen from Kerrek SB's answer
template <typename T, typename ...>
struct tmpl_rebind {
typedef T type;
};
template <template <typename ...> class Tmpl, typename ...T, typename ...Args>
struct tmpl_rebind<Tmpl<T...>, Args...> {
typedef Tmpl<Args...> type;
};
// end of stolen code
template <typename Container,
typename Func,
typename TargetType = typename std::result_of<Func(typename Container::value_type)>::type,
typename NewContainer = typename tmpl_rebind<Container, TargetType>::type >
NewContainer convert(const Container& c, Func f) {
NewContainer nc;
std::transform(std::begin(c), std::end(c), std::inserter(nc, std::end(nc)), f);
return nc;
}
int main() {
std::vector<int> vi{ 1, 2, 3, 4, 5 };
auto vs = convert(vi, [] (int i) { return std::to_string(i); });
assert( vs == std::vector<std::string>( {"1", "2", "3", "4", "5"} ) );
return 0;
}
I have tested this code with gcc 4.7.2 and clang 3.5 and works as expected.
As Yakk points out, there are quite a few caveats with this code though: "... should your rebind replace all arguments, or just the first one? Uncertain. Should it recursively replace T0 with T1 in later arguments? Ie std::map<T0, std::less<T0>> -> std::map<T1, std::less<T1>>?" I also see traps with the above code (e.g. how to deal with different allocators, see also Useless' answer).
Nevertheless, I believe the above code is already useful for simple use cases. If we were writing a utility function to be submitted to boost, then I would be more motivated to investigate these issues further. But there is already an accepted answer so I consider the case closed.
Many thanks to Constructor, dyp and Yakk for pointing out my mistakes / missed opportunities for improvements.
I wrote a blog post to solve a similar problem recently. Using templates and the iterator interface was the route I chose to follow.
for_each:
To cut down on the amount of boilerplate, we're going to create a using clause that allows us to grab the type contained within an iterator:
template <typename IteratorType>
using ItemType = typename std::iterator_traits<typename IteratorType::iterator>::value_type;
With that in place, we can implement a helper function for_each like so:
template <typename IteratorType>
void for_each(IteratorType &items, std::function<void(ItemType<IteratorType> const &item)> forEachCb)
{
for (typename IteratorType::iterator ptr = items.begin(); ptr != items.end(); ++ptr)
forEachCb(*ptr);
}
transform_container:
Finally transform_container, could be implemented like so:
template <typename IteratorType, typename ReturnType>
ReturnType transform_container(IteratorType &items, std::function<ItemType<ReturnType>(ItemType<IteratorType> const &item)> mapCb)
{
ReturnType mappedIterator;
for_each<IteratorType>(items, [&mappedIterator, &mapCb](auto &item) { mappedIterator.insert(mappedIterator.end(), mapCb(item)); });
return mappedIterator;
}
Which will allow us to call your two examples in the following way:
std::vector<int> vi{ 1, 2, 3, 4, 5 };
auto vs = transform_container<std::vector<int>, std::vector<std::string>>(vi, [](int i){return std::to_string(i);});
assert(vs == std::vector<std::string>({"1", "2", "3", "4", "5"}));
std::set<int> si{ 5, 10, 15 };
auto sd = transform_container<std::set<int>, std::set<double>>(si, [] (int i) { return i / 2.; });
assert(sd == std::set<double>({5/2., 10/2., 15/2.}));
My blog post also goes into a little more detail if that's helpful.

Using a static_assert to determine if a specific template parameter is a specific untyped class template

I'd like to have a function that restricts the parameters to be only types that derive from a specific templated class. In this case, basic_string (from the STL-docs). For example, a wstring is declared:
typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >
wstring;
The basic idea would be something like this:
template <class TString>
void strings_only_please(TString message) {
static_assert(is_base_of<basic_string, TString>::value,
"Not a string type!");
}
Of course, that doesn't compile though as basic_string hasn't been specified ... it needs a real type. (While I could likely just hard code the few actual string types, I'm looking for a general solution to this pattern.)
I'm using Visual Studio 2012 and would ideally like the code to be portable to other modern C++ compilers, like GCC.
There are three ways of solving your problem, one would be an implementation of is_specialization_of, the other involves making your function take a std::basic_string<T1,T2,T3> instead of TString, and the third has the same philosophy as the 2nd solution; make a template matchable only by std::basic_string.
is_base_of isn't sufficient in your example because of two reasons:
is_base_of is used to see if type U is derived from T (or if it's the same type), in your snippet there is no inheritance involved.
std::basic_string isn't a complete type and therefore can't be used with is_base_of at all (which you already pointed out).
solution #1
is_specialization_of would be used to check whether type U is a specialization of the incomplete type T. It's quite easy to implement it using a template-template class, as in the below example.
as noted by #SebastianRedl variadic templates are not available using VS2012, see the other solutions (which are not as generic but still sufficient to your needs).
#include <type_traits>
#include <iostream>
#include <string>
template<template<typename...> class T, typename U>
struct is_specialization_of : std::false_type { };
template<template<typename...> class T, typename... Ts>
struct is_specialization_of<T, T<Ts...>> : std::true_type { };
int
main (int argc, char *argv[])
{
std::cerr << is_specialization_of<std::basic_string, std::string >::value << std::endl;
std::cerr << is_specialization_of<std::basic_string, std::wstring>::value << std::endl;
std::cerr << is_specialization_of<std::basic_string, std::istream>::value << std::endl;
}
output
1
1
0
solution #2
template <typename T1, typename T2, typename T3>
void strings_only_please(std::basic_string<T1,T2,T3>) {
// ...
}
Sure, the above won't result in a nice static_assert error - but it is sufficient for your needs and does what you want; the function is only callable by types who specialize std::basic_string.
solution #3
template<typename T>
struct is_basic_string : std::false_type { };
template<typename T1, typename T2, typename T3>
struct is_basic_string<std::basic_string<T1,T2,T3>> : std::true_type { };
...
is_basic_string<std::string >::value // true
is_basic_string<std::istream>::value // false

Check if parameter pack contains a type

I was wondering if C++0x provides any built-in capabilities to check if a parameter pack of a variadic template contains a specific type. Today, boost:::mpl::contains can be used to accomplish this if you are using boost::mpl::vector as a substitute for variadic templates proper. However, it has serious compilation-time overhead. I suppose, C++0x has compiler-level support for std::is_same. So I was thinking if a generalization like below is also supported in the compiler.
template <typename... Args, typename What>
struct is_present
{
enum { value = (What in Args...)? 1 : 0 };
};
Fortunately, the C++ standard has evolved. With C++1z aka C++17, you can finally iterate easily over parameter packs. So the code for the answer is (almost) as simple, as suggested in the question:
template<typename What, typename ... Args>
struct is_present {
static constexpr bool value {(std::is_same_v<What, Args> || ...)};
};
The weird-looking (std::is_same_v<What, Args> || ...) is expanded by the compiler internally to (std::is_same_v<What, Args[0]> || std::is_same_v<What, Args[1]> || ...), which is exactly, what you want. It even correctly yields false with an empty Args parameter pack.
It is even possible to do the whole check inline in a function or method - no helper structs are required anymore:
template<typename T, typename ... List>
void foo(T t, List ... lst)
{
if constexpr((std::is_same_v<T, List> || ...)) {
std::cout << "T is in List" << std::endl;
} else {
std::cout << "T is not in List" << std::endl;
}
}
Note: This has been taken from another question, that was marked as a duplicate of this question. As this is the "canonical" question for this topic, I added that important information here.
No, you have to use (partial) specialization with variadic templates to do compile-time computations like this:
#include <type_traits>
template < typename Tp, typename... List >
struct contains : std::true_type {};
template < typename Tp, typename Head, typename... Rest >
struct contains<Tp, Head, Rest...>
: std::conditional< std::is_same<Tp, Head>::value,
std::true_type,
contains<Tp, Rest...>
>::type {};
template < typename Tp >
struct contains<Tp> : std::false_type {};
There is only one other intrinsic operation for variadic templates and that is the special form of the sizeof operator which computes the length of the parameter list e.g.:
template < typename... Types >
struct typelist_len
{
const static size_t value = sizeof...(Types);
};
Where are you getting "it has serious compilation-time overhead" with boost mpl from? I hope you are not just making assumptions here. Boost mpl uses techniques such as lazy template instantiation to try and reduce compile-times instead of exploding like naive template meta-programming does.
If you want to avoid manual type recursion, std::common_type appears to me to be the only utility in the STL which is a variadic template, and hence the only one which could potentially encapsulate recursion.
Solution 1
std::common_type finds the least-derived type in a set of types. If we identify numbers with types, specifically high numbers with less-derived types, it finds the greatest number in a set. Then, we have to map equality to the key type onto a level of derivation.
using namespace std;
struct base_one { enum { value = 1 }; };
struct derived_zero : base_one { enum { value = 0 }; };
template< typename A, typename B >
struct type_equal {
typedef derived_zero type;
};
template< typename A >
struct type_equal< A, A > {
typedef base_one type;
};
template< typename Key, typename ... Types >
struct pack_any {
enum { value =
common_type< typename type_equal< Key, Types >::type ... >::type::value };
};
Solution 2
We can hack common_type a little more. The standard says
A program may specialize this trait if
at least one template parameter in the
specialization is a user-defined type.
and describes exactly what is inside it: a recursive partial specialization case, a case which applies a binary operator, and a terminal case. Essentially, it's a generic fold function, and you can add whatever binary operation you please. Here I used addition because it's more informative than OR. Note that is_same returns an integral_constant.
template< typename Addend >
struct type_sum { // need to define a dummy type to turn common_type into a sum
typedef Addend type;
};
namespace std { // allowed to specialize this particular template
template< typename LHS, typename RHS >
struct common_type< type_sum< LHS >, type_sum< RHS > > {
typedef type_sum< integral_constant< int,
LHS::type::value + RHS::type::value > > type; // <= addition here
};
}
template< typename Key, typename ... Types >
struct pack_count : integral_constant< int,
common_type< type_sum< is_same< Key, Types > > ... >::type::type::value > {};