I'd like to be able to check invariants for classes that are used in metaprograms. My first naive approach was
template <int N>
struct digit
{
static_assert((N >= 0) && (N < 10), "bad invariant");
};
using boom = digit<99>;
However this compiles without any problems. The static assertion is triggered only when the illegal class is constructed.
It is possible when adding an additional template parameter:
#include <type_traits>
template <int N,
typename = typename std::enable_if<(N >= 0) && (N < 10)>::type>
struct digit;
using crash = digit<-7>;
When I wanted to apply this technique to a class that is used as a list of types:
#include <type_traits>
template <typename ...> struct are_integral;
template <typename T, typename ...Ts>
struct are_integral<T, Ts...>
{
static const bool value = std::is_integral<T>::value &&
are_integral<Ts...>::value;
};
template <>
struct are_integral<> : std::true_type { };
template <typename ...Ts,
typename = typename std::enable_if<are_integral<Ts...>::value>::type>
struct list;
using ok = list<int, long, char>;
using bad = list<double>;
It simply does not work since gcc complains that
error: parameter pack 'Ts' must be at the end of the template
parameter list struct list;
Even if it would work, the class is useless as the template parameter pack does not reflect the typelist.
So I tried to use an "illegal" base class:
template <typename> struct check;
template <typename ...Ts>
struct list : check<typename std::enable_if<are_integral<Ts...>::value>::type>
{ };
using ok = list<int, long, char>;
using bad = list<double>;
This compiles without problems.
Is there any way to accomplish something like that in c++11 or do I have to wait for concepts?
Your problem arises because the template is not instantiated when it is aliased, so the static_assert does not trigger.
If this is acceptable, you could add some indirection and use a builder metafunction to create your compile-time list. This metafunction would perform the check.
template <typename ...Ts>
struct make_list
{
static_assert(are_integral<Ts...>::value, "all types must be integral");
typedef list<Ts...> type;
};
using ok = make_list<int, long, char>::type;
using bad = make_list<double>::type;
Another solution is to use a dummy type to wrap your parameter pack into a first-class type.
// dummy wrapper
template <typename ...>
struct pack;
template <typename ...> struct are_integral;
// specialization for wrapped packs
template <typename ...Ts>
struct are_integral<pack<Ts...>> : are_integral<Ts...>
{
};
template <typename T, typename ...Ts>
struct are_integral<T, Ts...>
{
static const bool value = std::is_integral<T>::value &&
are_integral<Ts...>::value;
};
template <>
struct are_integral<> : std::true_type { };
// helper type which performs the check
template <typename Pack,
typename = typename std::enable_if<are_integral<Pack>::value>::type>
struct list_helper;
// actual type (alias) you will expose
template <typename ...Ts>
using list = list_helper<pack<Ts...>>;
using ok = list<int, long, char>;
using bad = list<double>; // compiler error
Using a wrapper often comes in handy when dealing with parameter packs, because it makes them more amenable to manipulation: the wrapper is a type like any other, which can be stored, appear anywhere in the parameter list, be passed to unary metafunctions, etc.
Related
I'm working with several different variant implementations, and I need to be able to convert between them. Specifically, std::variant, _variant_t, and a few others.
I'm trying to create a list of types to use as both a way to instantiate std::variants, and as a means to iterate through a list of types in a function to check if std::variant holds a value of that particular type.
My initial thought was something like this:
template <typename ...Args>
struct type_list{
}
I would like to use this as such, then use variadic recursion in a function to test and return the appropriate _variant_t. I won't have a problem with the function implementations if I could just find a way to extract the types from the type list.
using unsigned_types = typelist<uint8_t, uint16_t, uint32_t>;
using unsigned_variant = std::variant<unsigned_types::types>;
template <typename T, typename ...Args>
_variant_t to_variant_t(unsigned_variant& var) {
// auto val = std::get_if<T>(&var);
}
template<typename ...Args>
_variant_t to_variant_t(unsigned_variant& var) {
// Iterate over Args types to check if variant contains type
}
// Example syntax
int main() {
auto std_var = unsigned_variant((uint8_t)42);
auto _var = to_variant_t<unsigned_types::types>();
}
Here is the brute force way I could do this, but I feel it could be more elegant and less repetitive using templates, hence the above constructs.
_variant_t to_variant_t(const unsigned_variant& variant) {
auto uint8_ptr = std::get_if<uint8_t>(&variant);
if (uint8_ptr != nullptr)
return _variant_t((unsigned char)*uint8_ptr);
auto uint16_ptr = std::get_if<uint16_t>(&variant);
if (uint16_ptr != nullptr)
return _variant_t((unsigned short)*uint16_ptr);
// And so on for each unsigned integer type
}
How do I go about storing and extracting the types from type_list? I've tried the following:
template <typename ...Args>
struct type_list{
using types = Args...; // Parameter pack cannot be expanded in this context.
}
But obviously it doesn't compile. I'm missing something here. Any ideas?
You can write a meta function like
template <typename... Types>
auto variant_from_type_list(type_list<Types...>) -> std::variant<Types...>;
and combined with an helper alias of
template <typename TypeList>
using variant_from_type_list_t = decltype(variant_from_type_list(std::declval<TypeList>()));
lets you do
using unsigned_variant = variant_from_type_list_t<unsigned_types>;
You might have your transformation directly in your type_list:
template <typename ...Args>
struct type_list{
template <template <typename...> class C>
using transform_into = C<Args...>;
};
And then
using unsigned_types = type_list<uint8_t, uint16_t, uint32_t>;
using unsigned_variant = unsigned_types::transform_into<std::variant>;
Demo
Parameter packs cannot be stored directly, unfortunately.
Extraction is usually done using partial specialization.
#include <stdint.h>
#include <variant>
template <typename... Args> struct type_list {};
template <template <typename...> class var_impl, typename tlist>
struct make_var {};
template <template <typename...> class var_impl, typename... Args>
struct make_var<var_impl, type_list<Args...>> {
using type = var_impl<Args...>;
};
template <template <typename...> class var_impl, typename tlist>
using make_var_t = typename make_var<var_impl, tlist>::type;
template <typename tlist>
using make_std_var_t = typename make_var<std::variant, tlist>::type;
using unsigned_types = type_list<uint8_t, uint16_t, uint32_t>;
using unsigned_variant = make_std_var_t<unsigned_types>;
static_assert(std::is_same_v<unsigned_variant,
std::variant<uint8_t, uint16_t, uint32_t>>);
Use class template partial specializationto extract types of typelist
#include <variant>
#include <cstdint>
template <typename... Args>
struct typelist{};
template <typename TypeList, template <typename...> typename Template>
struct transform_to;
template <
template <typename...> typename TypeList,
typename... Args,
template <typename...> typename Template>
struct transform_to<TypeList<Args...>, Template> {
using type = Template<Args...>;
};
using unsigned_types = typelist<uint8_t, uint16_t, uint32_t>;
using unsigned_variant = transform_to<unsigned_types, std::variant>::type;
static_assert(
std::is_same_v<unsigned_variant, std::variant<uint8_t, uint16_t, uint32_t>>);
Demo
I've been trying to define an auxiliary class to help me work with template methods in which I would like a generic implementation both for complex and real types.
That has been my attempt so far:
#include<type_traits>
#include<complex>
template<class T>
struct is_complex{ static constexpr bool value = false;};
template<class T>
struct is_complex<std::complex<T>> :
std::integral_constant<bool,
std::is_integral<T>::value ||
std::is_floating_point<T>::value>{};
template<class T>
struct is_arithmetic:
std::integral_constant<bool,
std::is_integral<T>::value ||
std::is_floating_point<T>::value ||
is_complex<T>::value>{};
template<class T,
typename std::enable_if_t<is_arithmetic<T>::value,int> =0>
struct real_type {typedef T type;};
template<class T>
struct real_type<typename std::complex<T>>{typedef T type;};
I want to get something like
typename real_type<std::complex<double>> myVar1;//myVar1 is double
typename real_type<double> myVar2;//myVar2 is double
I was able to make it work as long as I didn't care that non-arithmetic types also had real_type<T>::type. But now that I have added this additional constraint, I cannot make it work and I don't really see why.
To clarify: I would like that calls like real_type<std::string>::type would generate compile-time errors. I want these calls to be valid only to arithmetic (including complex) and integral types.
The compiler error of my latest attempt was:
non-type template argument specializes a template parameter with dependent type 'typename std::enable_if_t<is_arithmetic<T>::value, int>' (aka 'typename enable_if<is_arithmetic<T>::value, int>::type')
But I don't know how to deal with it. If this information is useful, I have access to compilers supporting C++17.
Usually this is done with specialization and a template defaulted parameter.
I mean
template <typename, typename = void>
struct real_type;
template <typename T>
struct real_type<T, std::enable_if_t<std::is_arithmetic_v<T>>>
{ using type = T; };
template <typename T>
struct real_type<std::complex<T>, void>
{ using type = T; };
where you have a separate specialization for std::complex and, as observed by Patrick Roberts (thanks), without std::complex your is_arithmetic become a duplicate of std::is_arithmetic (so is better directly use std::is_arithmetic).
You get
real_type<int> r1; // compile
real_type<std::complex<float>> r2; // compile
//real_type<std::string> r3; // compilation error
May I suggest a slightly more concise implementation that works more generally (which requires c++17):
#include <type_traits>
// catch all for single parameters that have 0 template parameters
template <typename T>
struct real_type{
static_assert(std::is_arithmetic_v<T>);
using type = T;
};
template <typename T>
using real_type_t = typename real_type<T>::type;
// magically catch anything which matches V<T, Ts...> and exposes T as `type`
template <template <typename...> typename V, typename T, typename...Ts>
struct real_type<V<T, Ts...>>{
using type = real_type_t<T>;
};
#include <vector>
#include <complex>
using d = real_type_t<double>;
static_assert(std::is_same_v<d, double>);
using d2 = real_type_t<std::vector<double>>;
static_assert(std::is_same_v<d2, double>);
using d3 = real_type_t<std::complex<double>>;
static_assert(std::is_same_v<d3, double>);
// doesn't compile
struct NotValid {};
using d4 = real_type_t<std::vector<NotValid>>;
I'm trying to write a Bind metaprogramming template helper metafunction that binds a template parameter to something.
I have a working implementation for simple template metafunctions:
template<typename T0, typename T1>
struct MakePair
{
using type = std::pair<T0, T1>;
};
template<template<typename...> class TF, typename... Ts>
struct Bind
{
template<typename... TArgs>
using type = TF<Ts..., TArgs...>;
};
using PairWithInt = typename Bind<MakePair, int>::type;
static_assert(std::is_same<PairWithInt<float>, MakePair<int, float>>{}, "");
But what if MakePair's template arguments were template templates? Or simple numerical values?
template<template<typename> class T0, template<typename> class T1>
struct MakePair0
{
using type = /*...*/;
};
template<template<typename...> class TF, template<typename> class... Ts>
struct Bind0 { /*...*/ }
// ...
template<int T0, int T1>
struct MakePair1
{
using type = /*...*/;
};
template<template<int...> class TF, int... Ts>
struct Bind1 { /*...*/ }
A lot of unnecessary repetition. It gets unmanageable if template arguments are mixed between types, template templates, and integral constants.
Is something like the following piece of code possible?
template<template<ANYTHING...> class TF, ANYTHING... Ts>
struct BindAnything
{
template<ANYTHING... TArgs>
using type = TF<Ts..., TArgs...>;
};
ANYTHING would accept types, template templates, template template templates, integral values, etc...
When I'm doing serious metaprogramming, I turn everything into types.
template<class T>struct tag{using type=T;};
template<class Tag>using type_t=typename Tag::type;
template<template<class...>class> struct Z {};
template<class Z, class...Ts>
struct apply {};
template<template<class...>class z, class...ts>
struct apply< Z<z>, ts... >:
tag< z<ts...> >
{};
template<class Z, class...Ts>
using apply_t = type_t< apply<Z, Ts...> >;
now we pass template<?> foo around as Z<foo>, and it is now a type.
Similar things can be done for constants, using std::integral_constant<T, t> (and easier to use aliases of same), or template<class T, T* p> struct pointer_constant {};, by turning them into types.
Once everything is a type, your metaprogramming becomes more uniform. Templates just become a kind of type on which apply_t does things to.
There is no way in C++ to have a template argument that can be a type, a value or a template. So this is about the best you can get.
templates not written for the above pattern need to be wrapped up, and their arguments "lifted" to being types. As an example:
template<class T, class t>
using number_constant = std::integral_constant< T, t{} >;
using number_constant_z = Z<number_constant>;
has had its arguments "lifted" from values to types, and then it has been wrapped with a Z to turn itself into a type.
Bind now reads:
template<class z, class... Ts>
struct Bind {
template<class... More>
using type_base = apply_t< z, Ts..., More... >;
using type = Z<type_base>;
};
template<class Z, class...Ts>
using Bind_t = type_t<Bind<Z,Ts...>>; // strip ::type
using Bind_z = Z<Bind_t>; // quote into a Z<?>
and Bind_z is a type wrapping a template that returns a wrapped template, and takes a type that wraps a template as its first argument.
To use it:
template<class...>struct types{using type=types;};
using types_z=Z<types>;
template<class...Ts>
using prefix =apply_t< Bind_z, types_z, Ts... >;
using prefix_z = Z<prefix>;
prefix_z takes a set of types, and generates a factory of types<?...> that will contain the prefix Ts... first.
apply_t< apply_t< prefix_z, int, double, char >, std::string >
is
types< int, double, char, std::string >
live example.
There is another fun approach: do metaprogramming in functions:
template<template<class...>class z, class...Ts>
constexpr auto apply_f( Z<z>, tag<Ts>... )
-> tag<z<Ts...>> { return {}; }
here, types are represented by values of type tag<t>, templates a Z<z> and values as std::integral_constant<?>.
These two:
template<class T>
constexpr tag<T> Tag = {};
template<template<class...>class z>
constexpr Z<z> Zag = {};
give you ways to get values that represent types and templates respectively.
#define TYPEOF(...) type_t<decltype(__VA_ARGS__)>
is a macro that moves from an instance of a tag to type type in the tag, and Tag<?> moves from a type to an instance of a tag.
TYPEOF( apply_f( apply_f( Zag<prefix>, Tag<int>, Tag<double>, Tag<char> ), Tag<std::string> ) )
is
apply_t< apply_t< prefix_z, int, double, char >, std::string >
strange, but can be interesting.
I think you're looking for quote and map here. First, you want something that given a "metafunction class" and a sequence of arguments gives you a new type:
template <typename MCls, typename... Args>
using map = typename MCls::template apply<Args...>;
As the implementation here suggests, a metafunction class is one that has an member alias template named apply.
To turn a class template into a metafunction class, we introduce quote:
template <template <typename...> class C>
struct quote {
template <typename... Args>
using apply = C<Args...>;
};
The above is sufficient to do something like:
using T = map<quote<std::tuple>, int, char, double>;
to yield the type:
std::tuple<int, char, double>
In your example, we could write:
using P = map<quote<MakePair>, int, char>::type; // std::pair<int, char>
but I would instead prefer to make MakePair a metafunction class directly:
struct MakePair2 {
template <typename T, typename U>
using apply = std::pair<T, U>;
};
using P = map<MakePair2, int, char>; // also std::pair<int, char>
that avoids the extra ::type.
Consistently use the concepts of metafunction (a type with a member typedef named type, e.g. map) and a metafunction class (a type with a member template alias named apply, e.g. quote) and use only those concepts throughout your metaprogramming code. Values and class templates are second-class citizens.
Is there any way in c++ to iterate over function parameter types in compile time? I want to do something like this:
struct null_type {};
float foo(int, bool, char);
get_param_type<foo, 0>::type float_var; // return type
get_param_type<foo, 1>::type int_var; // first arg type
get_param_type<foo, 2>::type bool_var; // second arg type
get_param_type<foo, 3>::type char_var; // third arg type
get_param_type<foo, 4>::type null_type_var;
You can easily write this yourself. First, pack the function parameter types into a tuple:
#include <tuple>
template <typename> struct FnArgs;
template <typename R, typename ...Args>
struct FnArgs<R(Args...)>
{
using type = std::tuple<Args...>;
};
Now you can use the standard tuple API to access the elements:
using FT = FnArgs<decltype(foo)>::type;
std::tuple_element<0, FT> x;
A further specialization for pointers-to-member-function is easily added should you need one.
(You cannot easily get around the decltype, since there is no type deduction for non-type template parameters (yet).)
Here's a version which uses your null_type for out-of-bounds indices:
template <typename, std::size_t, typename = void>
struct get_param_type
{
using type = null_type;
};
template <typename Ret, typename... Args, std::size_t N>
struct get_param_type<Ret(Args...), N, std::enable_if_t<N < (1+sizeof...(Args))>>
{
using type = typename std::tuple_element<N,std::tuple<Ret,Args...>>::type;
};
This is more of a conceptual question. I'm trying to find the easiest way of converting a two-arg template (the arguments being types) into a one-arg template. I.e., binding one of the types.
This would be the meta-programming equivalent of bind in boost/std. My example includes a possible use-case, which is, passing std::is_same as template argument to a template that takes a one-arg template template argument (std::is_same being a two-arg template), i.e. to TypeList::FindIf. The TypeList is not fully implemented here, neither is FindIf, but you get the idea. It takes a "unary predicate" and returns the type for which that predicate is true, or void if not such type.
I have 2 working variants but the first is not a one-liner and the 2nd uses a rather verbose BindFirst contraption, that would not work for non-type template arguments. Is there a simple way to write such a one-liner? I believe the procedure I'm looking for is called currying.
#include <iostream>
template<template<typename, typename> class Function, typename FirstArg>
struct BindFirst
{
template<typename SecondArg>
using Result = Function<FirstArg, SecondArg>;
};
//template<typename Type> using IsInt = BindFirst<_EqualTypes, int>::Result<Type>;
template<typename Type> using IsInt = std::is_same<int, Type>;
struct TypeList
{
template<template<typename> class Predicate>
struct FindIf
{
// this needs to be implemented, return void for now
typedef void Result;
};
};
int main()
{
static_assert(IsInt<int>::value, "");
static_assert(!IsInt<float>::value, "");
// variant #1: using the predefined parameterized type alias as predicate
typedef TypeList::FindIf<IsInt>::Result Result1;
// variant #2: one-liner, using BindFirst and std::is_same directly
typedef TypeList::FindIf< BindFirst<std::is_same, int>::Result>::Result Result2;
// variant #3: one-liner, using currying?
//typedef TypeList::FindIf<std::is_same<int, _>>::Result Result2;
return 0;
}
Click here for code in online compiler GodBolt.
I think the typical way of doing this is keep everything in the world of types. Don't take template templates - they're messy. Let's write a metafunction named ApplyAnInt that will take a "metafunction class" and apply int to it:
template <typename Func>
struct ApplyAnInt {
using type = typename Func::template apply<int>;
};
Where a simple metafunction class might be just checking if the given type is an int:
struct IsInt {
template <typename T>
using apply = std::is_same<T, int>;
};
static_assert(ApplyAnInt<IsInt>::type::value, "");
Now the goal is to support:
static_assert(ApplyAnInt<std::is_same<_, int>>::type::value, "");
We can do that. We're going to call types that contain _ "lambda expressions", and write a metafunction called lambda which will either forward a metafunction class that isn't a lambda expression, or produce a new metafunction if it is:
template <typename T, typename = void>
struct lambda {
using type = T;
};
template <typename T>
struct lambda<T, std::enable_if_t<is_lambda_expr<T>::value>>
{
struct type {
template <typename U>
using apply = typename apply_lambda<T, U>::type;
};
};
template <typename T>
using lambda_t = typename lambda<T>::type;
So we update our original metafunction:
template <typename Func>
struct ApplyAnInt
{
using type = typename lambda_t<Func>::template apply<int>;
};
Now that leaves two things: we need is_lambda_expr and apply_lambda. Those actually aren't so bad at all. For the former, we'll see if it's an instantiation of a class template in which one of the types is _:
template <typename T>
struct is_lambda_expr : std::false_type { };
template <template <typename...> class C, typename... Ts>
struct is_lambda_expr<C<Ts...>> : contains_type<_, Ts...> { };
And for apply_lambda, we just will substitute the _ with the given type:
template <typename T, typename U>
struct apply_lambda;
template <template <typename...> class C, typename... Ts, typename U>
struct apply_lambda<C<Ts...>, U> {
using type = typename C<std::conditional_t<std::is_same<Ts, _>::value, U, Ts>...>::type;
};
And that's all you need actually. I'll leave extending this out to support arg_<N> as an exercise to the reader.
Yeah, I had this issue to. It took a few iterations to figure out a decent way to do this. Basically, to do this, we need to specify a reasonable representation of what we want and need. I borrowed some aspects from std::bind() in that I want to specify the template that I wish to bind and the parameters that I want to bind to it. Then, within that type, there should be a template that will allow you to pass a set of types.
So our interface will look like this:
template <template <typename...> class OP, typename...Ts>
struct tbind;
Now our implementation will have those parameters plus a container of types that will be applied at the end:
template <template <typename...> class OP, typename PARAMS, typename...Ts>
struct tbind_impl;
Our base case will give us a template type, which I'll call ttype, that'll return a template of the contained types:
template <template <typename...> class OP, typename...Ss>
struct tbind_impl<OP, std::tuple<Ss...>>
{
template<typename...Us>
using ttype = OP<Ss...>;
};
Then we have the case of moving the next type into the container and having ttype refer to the ttype in the slightly simpler base case:
template <template <typename...> class OP, typename T, typename...Ts, typename...Ss>
struct tbind_impl<OP, std::tuple<Ss...>, T, Ts...>
{
template<typename...Us>
using ttype = typename tbind_impl<
OP
, std::tuple<Ss..., T>
, Ts...
>::template ttype<Us...>;
};
And finally, we need a remap of the templates that will be passed to ttype:
template <template <typename...> class OP, size_t I, typename...Ts, typename...Ss>
struct tbind_impl<OP, std::tuple<Ss...>, std::integral_constant<size_t, I>, Ts...>
{
template<typename...Us>
using ttype = typename tbind_impl<
OP
, typename std::tuple<
Ss...
, typename std::tuple_element<
I
, typename std::tuple<Us...>
>::type
>
, Ts...
>::template ttype<Us...>;
Now, since programmers are lazy, and don't want to type std::integral_constant<size_t, N> for each parameter to remap, we specify some aliases:
using t0 = std::integral_constant<size_t, 0>;
using t1 = std::integral_constant<size_t, 1>;
using t2 = std::integral_constant<size_t, 2>;
...
Oh, almost forgot the implementation of our interface:
template <template <typename...> class OP, typename...Ts>
struct tbind : detail::tbind_impl<OP, std::tuple<>, Ts...>
{};
Note that tbind_impl was placed in a detail namespace.
And voila, tbind!
Unfortunately, there is a defect prior to c++17. If you pass tbind<parms>::ttype to a template that expects a template with a particular number of parameters, you will get an error as the number of parameters don't match (specific number doesn't match any number). This complicates things slightly requiring an additional level of indirection. :(
template <template <typename...> class OP, size_t N>
struct any_to_specific;
template <template <typename...> class OP>
struct any_to_specific<OP, 1>
{
template <typename T0>
using ttype = OP<T0>;
};
template <template <typename...> class OP>
struct any_to_specific<OP, 2>
{
template <typename T0, typename T1>
using ttype = OP<T0, T1>;
};
...
Using that to wrap tbind will force the compiler to recognize the template having the specified number of parameters.
Example usage:
static_assert(!tbind<std::is_same, float, t0>::ttype<int>::value, "failed");
static_assert( tbind<std::is_same, int , t0>::ttype<int>::value, "failed");
static_assert(!any_to_specific<
tbind<std::is_same, float, t0>::ttype
, 1
>::ttype<int>::value, "failed");
static_assert( any_to_specific<
tbind<std::is_same, int , t0>::ttype
, 1
>::ttype<int>::value, "failed");
All of which succeed.