I have the following code:
template <template <typename, typename...> typename trait_t, typename arg_t>
struct BindFirst
{
template <typename... arg_ts>
using result_t = trait_t<arg_t, arg_ts...>;
};
#define BIND_FIRST(trait_t, arg_t) BindFirst<trait_t, arg_t>::template result_t
you can use it to bind the first argument of a trait like this:
BIND_FIRST(std::is_same, double)
The result is equivalent to:
template <typename T>
struct IsInt : std::is_same<double, T> { };
The difference is, that you can use it inline. For example like this:
using result_t = find_t<type_list, BIND_FIRST(std::is_same, double)>;
This works but i like to avoid the define. I tried to use an alias. But I have no idea how to apply it. Is there any way to replace the define?
You can use templates with using to create an alias template, just like you did for result_t.
template <typename... Args>
using IsDouble = BindFirst<std::is_same, double>::template result_t<Args...>;
You can limit the Args... to a single type T as well, it doesn't have to be variadic.
Edit: If your goal is to reduce boilerplate, you may want to opt for something like this
template <typename T, typename U>
using IsSameAs = std::is_same<T, U>;
template <typename T>
using IsDouble = IsSameAs<double, T>;
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
Is there any way one can alias a nested template class with a using keyword? Something like this
template <typename... Types>
struct Something {
template <typename... TypesTwo>
struct Another {};
};
template <typename... Types>
template <typename... TypesTwo>
using Something_t = typename Something<Types...>::template Another<TypesTwo...>;
int main() {
Something_t<int><double>{};
return 0;
}
This answer template template alias to a nested template? shows a way to do that but that will no longer work if both the parameter packs are variadic, as the compiler will not know where to start and where to end the type lists.
Not exactly what you asked but... if you can wrap your variadic type lists as arguments of tuples (or similar classes)...
#include <tuple>
template <typename ... Types>
struct Something
{
template <typename ... TypesTwo>
struct Another {};
};
template <typename, typename>
struct variadicWrapper;
template <typename ... Ts1, typename ... Ts2>
struct variadicWrapper<std::tuple<Ts1...>, std::tuple<Ts2...>>
{ using type = typename Something<Ts1...>::template Another<Ts2...>; };
template <typename T1, typename T2>
using Something_t = typename variadicWrapper<T1, T2>::type;
int main()
{
Something_t<std::tuple<int>, std::tuple<double>>{};
}
Not a standalone answer, but an addition to max66's answer:
You could have tried this:
template<typename ... TT, typename ... TTT>
using Alias = typename Something<TT...>::Another<TTT...>;
Looks really nice at first, doesn't it?
Problem then, however will already be with one single template parameter:
Alias<int> a;
Which one is it now? Something<int>::Another<> or Something<>::Another<int>? And if you have more parameters, how to distribute? No chance to get a meaningful solution. So no, you can't do that directly, you have to help yourself with tricks such as max66 proposed...
A class template can have multiple parameters that all have defaults.
template<typename UnderlyingT0 = int, typename UnderlyingtT1 = long, typename StringT = std::string>
struct options;
Instatiating the template with just default parameters is easy:
options<> my_default_options;
But what if I want to change a subset of parameters?
options<int, int, std::wstring> wstring_options;
It is not obvious that int is a default for the first parameter while for the second it isn't. Is there something like
options<default, int, std::wstring> wstring_options;
in C++?
No, there is nothing in standard C++ which would enable this. One option, noted by #FlorisVelleman in the comments, is to introduce an alias template:
template <class UnderlyingT1, class StringT = std::string>
using options_defT0 = options<int, UnderlyingT1, StringT>;
This has the drawback of having to explicitly duplicate the default argument of UnderlyingT0 in the alias definition, but as least it' duplicated in one place only.
An alternative option is used by many Boost libraries. They introduce a special tag use_default and make that the default value. Something like this:
struct use_default {};
template<typename UnderlyingT0 = use_default, typename UnderlyingtT1 = use_default, typename StringT = use_default>
struct options
{
using RealUnderlyingT0 = typename std::conditional<
std::is_same<UnderlyingT0, use_default>::value,
int,
UnderlyingT0
>::type;
using RealUnderlyingT1 = typename std::conditional<
std::is_same<UnderlyingT1, use_default>::value,
long,
UnderlyingT1
>::type;
using RealStringT = typename std::conditional<
std::is_same<StringT, use_default>::value,
std::string,
StringT
>::type;
};
Here, the downsides are that 1. you cannot tell the default arguments by looking at the template declaration, and 2. options<> and options<int, long, std::string> are different types.
The former can be fixed by good documentation, and the latter can probably be helped by judicious use of conversion functions and base classes.
There isn't a way to reuse the default parameters directly. You can use Floris's comment as a way to provide shorthands for common uses, but the template alias will still repeat the defaults.
Alternatively, the options struct could be set up to allow switching out parameters:
template <typename UnderlyingT0 = int,
typename UnderlyingT1 = long,
typename StringT = std::string>
struct options {
template <typename NewT0>
using WithT0 = options<NewT0, UnderylingT1, StringT>;
template <typename NewT1>
using WithT1 = options<UnderylingT0, NewT1, StringT>;
template <typename NewStringT>
using WithStringT = options<UnderylingT0, UnderylingT1, NewStringT>;
};
And then use it as
options<>::WithT1<int>::WithStringT<std::wstring>
If all your template arguments have defaults like in your example, you could create a helper struct to extract them for you.
template <class T, size_t N>
struct default_for_helper;
template <template <typename...> class T, size_t N, typename... Args>
struct default_for_helper<T<Args...>, N>
{
using type = std::tuple_element_t<N, std::tuple<Args...>>;
};
template <template <typename...> class T, size_t N>
using default_for = typename default_for_helper<T<>, N>::type;
Then use it like this:
options<default_for<options,0>, int, std::string> o;
I came across this issue again and came up with a more general version of Sebastian Redl's solution.
//given an index to replace at, a type to replace with and a tuple to replace in
//return a tuple of the same type as given, with the type at ReplaceAt set to ReplaceWith
template <size_t ReplaceAt, typename ReplaceWith, size_t... Idxs, typename... Args>
auto replace_type (std::index_sequence<Idxs...>, std::tuple<Args...>)
-> std::tuple<std::conditional_t<ReplaceAt==Idxs, ReplaceWith, Args>...>;
//instantiates a template with the types held in a tuple
template <template <typename...> class T, typename Tuple>
struct type_from_tuple;
template <template <typename...> class T, typename... Ts>
struct type_from_tuple<T, std::tuple<Ts...>>
{
using type = T<Ts...>;
};
//replaces the type used in a template instantiation of In at index ReplateAt with the type ReplaceWith
template <size_t ReplaceAt, typename ReplaceWith, class In>
struct with_n;
template <size_t At, typename With, template <typename...> class In, typename... InArgs>
struct with_n<At, With, In<InArgs...>>
{
using tuple_type = decltype(replace_type<At,With>
(std::index_sequence_for<InArgs...>{}, std::tuple<InArgs...>{}));
using type = typename type_from_tuple<In,tuple_type>::type;
};
//convenience alias
template <size_t ReplaceAt, typename ReplaceWith, class In>
using with_n_t = typename with_n<ReplaceAt, ReplaceWith, In>::type;
Advantages:
Flexible selection of parameters to change
Doesn't require changing of the original class
Supports classes which have some parameters without defaults
options<int,long,int> and with_n_t<2,int,options<>> are the same type
Some usage examples:
with_n_t<1, int, options<>> a; //options<int, int, std::string>
with_n_t<2, int,
with_n_t<1, int, options<>>> b; //options<int, int, int>
You could further generalise this to take variadic pairs of indices and types so that you don't need to nest with_n_t.
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.
C++11 added alias templates such as:
template<typename T> using identity = T;
template<bool b, typename T = void> using EnableIf = typename std::enable_if<b, T>::type;
These are much easier to use than the old template type maps that give you the return value in a ::type field because even if your type arguments are dependent on the local context, you don't need to inform the compiler that the result is a type.
In effect, you hoist the typename from the location of use to the using alias.
Is there anything equivalent that can be used to get rid of produced extraneous templates?
Suppose you had a metafunction whose output was a class or alias template instead of a type. The current method is something like this:
template<typename T>
struct my_meta {
template<typename U>
using Template = identity<U>;
};
template<typename T>
struct my_meta {
template<typename U>
using Template = int;
};
which we can then use like this:
template<typename T, typename U>
typename my_meta<T>::template Template<U>
do_stuff( U&& ) { return {}; }
That extra template keyword in the return type exists to disambiguate the return value of my meta function is what I want to eliminate.
Is there any way to indicate to the compiler that the result of a metacomputation is another alias or class template in C++11 or C++1y, without using the template keyword at the location of invocation?
Ie:
template<typename T, typename U>
my_meta_template<T><U>
do_stuff( U&& ) { return {}; }
or even
template<template<typename> class Template>
void do_more_stuff() {}
template<typename T>
void do_stuff() {
// syntax I want: just produce an alias or class template directly:
do_more_stuff< my_meta_template<T> >();
// vs what I find is required: the disambiguator:
do_more_stuff< my_meta<T>::template Template >();
};
Best way I know to remove template is made simple warper that will do it for you:
template<typename Meta, typename U>
using apply = typename Meta::template Template<U>;
and every where you previously used template<typename> class Template replace it with typename Meta.
template<typename Meta>
void do_more_stuff()
{
apply<Meta, int>::func(); //=== Meta::template Template<int>::func();
}
template<typename T>
void do_stuff() {
do_more_stuff< my_meta<T> >();
do_more_stuff< my_meta<T> >();
};