transform_v2t function in the code below builds a tuple of template class A instances:
template <typename T>
struct A
{
T val;
};
template <class V, template <class> class T, std::size_t... index>
inline constexpr auto transform_v2t(std::index_sequence<index...>)
{
return std::make_tuple(T<std::variant_alternative_t<index, V>>() ...);
}
template <class V, template <class> class T>
inline constexpr auto transform_v2t()
{
return transform_v2t<V, T>(std::make_index_sequence<std::variant_size_v<V>>());
}
typedef std::variant<bool, char, int, float, double, std::string> V;
int main()
{
auto t1 = transform_v2t<V, A>();
}
is it possible to apply the same transform_v2t function to a class with two template arguments, for example:
template <typename P, typename T>
struct B
{
P other_val;
T val;
};
with P specialized as int?
with a pseudo code it can be something like this:
template <class T> typedef B<int, T> PartiallySpecializedB;
auto t2 = transform_v2t<V, PartiallySpecializedB>();
see online sample code.
Never use typedef in post-C++11 code, always prefer using (known as alias declarations).
Not only are they easier to read because the name you're declaring is on the left (as opposed to... wherever):
using V = std::variant<bool, char, int, float, double, std::string>;
... but they also have support for alias template declarations:
template <class T>
using PartiallySpecializedB = B<int, T>;
auto t2 = transform_v2t<V, PartiallySpecializedB>();
Related
To deduce the highest precision type for floating point and complex types, i.e.
float/double/long double results in long double,
std::complex<T> results in std::complex<long double>,
my attempt ( live example on Wandbox ) feels very clumsy:
#include <complex>
#include <type_traits>
template <typename T>
struct is_complex : std::false_type {};
template <std::floating_point T>
struct is_complex<std::complex<T>> : std::true_type {};
template <typename T>
inline constexpr bool is_complex_v = is_complex<T>::value;
template <typename T>
struct highest_precision_type
{
// none for arbitrary type
};
template <typename T>
requires std::is_floating_point_v<T>
struct highest_precision_type<T>
{
typedef long double type;
};
template <typename T>
requires is_complex_v<T>
struct highest_precision_type<T>
{
typedef std::complex<long double> type;
};
int main()
{
auto f = highest_precision_type<float>::type{1};
auto cf = highest_precision_type<std::complex<float>>::type{0, 1};
static_assert(std::is_same_v<decltype(f), long double> );
static_assert(std::is_same_v<decltype(cf), std::complex<long double>> );
}
Is there a more concise way to achieve the desired result?
Using std::conditional<> and #KamilCuk's comment reduces code to:
template <typename T>
struct highest_precision_type
: std::conditional<std::is_floating_point_v<T>, long double, T>
{
};
template <typename T>
struct highest_precision_type<std::complex<T>>
{
typedef std::complex<long double> type;
};
see live example.
I think your code is fine but if you'd like a more compact alternative, this could be done using std::conditional:
template <typename T>
struct highest_precision_type
{
static_assert(std::is_arithmetic_v<T>);
using type =
std::conditional_t<
std::is_unsigned_v<T>,
std::uintmax_t,
std::conditional_t<
std::is_integral_v<T>,
std::intmax_t,
long double>
>;
};
For types instantiated from templates, what Barry had in his now deleted answer looks good. This is my take on that:
template <template <typename...> class C, typename... Ts>
struct highest_precision_type<C<Ts...>>
{
using type = C<typename highest_precision_type<Ts>::type...>;
};
template <typename T>
using highest_precision_type_t = typename highest_precision_type<T>::type;
Demo
Note the part in the demo that does:
highest_precision_type_t<std::string> s;
static_assert(std::is_same_v<decltype(s), std::basic_string<std::intmax_t>>);
As you maybe know since C++ does not support list of types except in special cases most people just use tuple as ugly list of types.
So for example to check if some list contains only fp numbers one might do this:
template <typename T>
struct AllFp {};
template <typename... T>
struct AllFp<std::tuple<T...>> {
static constexpr bool value =
(std::is_floating_point_v<std::remove_cvref_t<T>> && ...);
};
While this might seem to work, it actually does not if users pass const std::tuple or reference to tuple.
#include<type_traits>
#include<tuple>
template <typename T>
struct AllFp {};
template <typename... T>
struct AllFp<std::tuple<T...>> {
static constexpr bool value =
(std::is_floating_point_v<std::remove_cvref_t<T>> && ...);
};
int main(){
static_assert(!AllFp<std::tuple<float, int, float>>::value);
static_assert(AllFp<std::tuple<float, long double, float>>::value);
// requires std::remove_cvref_t
//static_assert(AllFp<const std::tuple<float, long double, float>>::value);
//static_assert(AllFp<std::tuple<float, long double, float>&>::value);
}
Is there a way I can write the template so that "users"(people using AllFp) do not need to clean the type of tuple they pass?
note:tagging C++20 since I am ok with concepts solution.
With Boost.Mp11, this is a short one-liner (as always):
template <typename L>
using AllFp = mp_all_of<std::remove_cvref_t<L>, std::is_floating_point>;
Note that std::remove_cvref_t is actually C++20. For earlier standards, you can just do std::remove_cv_t<std::remove_reference_t<L>> or just std::decay_t<L> for brevity.
With corrected predicate:
template <typename T>
using decays_to_fp = std::is_floating_point<std::remove_cvref_t<T>>;
template <typename L>
using AllFp = mp_all_of<std::remove_cvref_t<L>, decays_to_fp>;
Or:
template <typename L>
using AllFp = mp_all_of_q<std::remove_cvref_t<L>,
mp_compose<std::remove_cvref_t, std::is_floating_point>>;
All you need is an additional level of indirection. Rename your primary template, and specialization, from AllFp to AllFp_Impl. Then make AllFp an alias template that does the job of removing the cvref qualifications from the tuple itself:
template <typename T>
using AllFp = AllFp_Impl<std::remove_cvref_t<T>>;
Here's a demo.
You can also use a sort of self-inheritance.
I mean: you can add following specializations
template <typename T>
struct AllFp<T const> : public AllFp<T>
{ };
template <typename T>
struct AllFp<T&> : public AllFp<T>
{ };
The following is a full compiling (no error from static_assert()) example that uses only std::remove_cv_t
#include<type_traits>
#include<tuple>
template <typename T>
struct AllFp {};
template <typename T>
struct AllFp<T const> : public AllFp<T>
{ };
template <typename T>
struct AllFp<T&> : public AllFp<T>
{ };
template <typename... T>
struct AllFp<std::tuple<T...>> {
static constexpr bool value =
(std::is_floating_point_v<std::remove_cv_t<T>> && ...);
};
int main(){
static_assert(!AllFp<std::tuple<float, int, float>>::value);
static_assert(AllFp<std::tuple<float, long double, float>>::value);
static_assert(AllFp<const std::tuple<float, long double, float>>::value);
static_assert(AllFp<std::tuple<float, long double, float>&>::value);
}
How to by a given variant type
using V = std::variant<bool, char, std::string, int, float, double, std::vector<int>>;
declare two variant types
using V1 = std::variant<bool, char, int, float, double>;
using V2 = std::variant<std::string, std::vector<int>>;
where V1 includes all the arithmetic types from V and V2 includes all non-arithmetic types from V?
V can be a parameter of a template class, for example:
template <class V>
struct TheAnswer
{
using V1 = ?;
using V2 = ?;
};
in general the criteria can be a constexpr variable like this:
template <class T>
constexpr bool filter;
With Boost.Mp11, this is a short one-liner (as always):
using V1 = mp_filter<std::is_arithmetic, V>;
using V2 = mp_remove_if<V, std::is_arithmetic>;
You can also use:
using V1 = mp_copy_if<V, std::is_arithmetic>;
to make the two more symmetric.
Alternatively,
using P = mp_partition<V, std::is_arithmetic>;
using V1 = mp_first<P>;
using V2 = mp_second<P>;
If for whatever reason you don't want to use Barry's short and reasonable answer, here is one that is neither (thanks #xskxzr for removing the awkward "bootstrap" specialization, and to #max66 for warning me against the empty variant corner case):
namespace detail {
template <class V>
struct convert_empty_variant {
using type = V;
};
template <>
struct convert_empty_variant<std::variant<>> {
using type = std::variant<std::monostate>;
};
template <class V>
using convert_empty_variant_t = typename convert_empty_variant<V>::type;
template <class V1, class V2, template <class> class Predicate, class V>
struct split_variant;
template <class V1, class V2, template <class> class Predicate>
struct split_variant<V1, V2, Predicate, std::variant<>> {
using matching = convert_empty_variant_t<V1>;
using non_matching = convert_empty_variant_t<V2>;
};
template <class... V1s, class... V2s, template <class> class Predicate, class Head, class... Tail>
struct split_variant<std::variant<V1s...>, std::variant<V2s...>, Predicate, std::variant<Head, Tail...>>
: std::conditional_t<
Predicate<Head>::value,
split_variant<std::variant<V1s..., Head>, std::variant<V2s...>, Predicate, std::variant<Tail...>>,
split_variant<std::variant<V1s...>, std::variant<V2s..., Head>, Predicate, std::variant<Tail...>>
> { };
}
template <class V, template <class> class Predicate>
using split_variant = detail::split_variant<std::variant<>, std::variant<>, Predicate, V>;
See it live on Wandbox
EDIT Given that a empty variant (std::variant<>) is ill formed (according cppreference) and that should be used std::variant<std::monostate> instead, I've modified the answer (added a tuple2variant() specialization for empty tuple) to support the case when the list of types for V1 or V2 is empty.
It's a little decltype() delirium but... if you declare a helper filter couple of function as follows
template <bool B, typename T>
constexpr std::enable_if_t<B == std::is_arithmetic_v<T>, std::tuple<T>>
filterArithm ();
template <bool B, typename T>
constexpr std::enable_if_t<B != std::is_arithmetic_v<T>, std::tuple<>>
filterArithm ();
and a tuple to variant function (with a specialization for empty tuples, to avoid a empty std::variant)
std::variant<std::monostate> tuple2variant (std::tuple<> const &);
template <typename ... Ts>
std::variant<Ts...> tuple2variant (std::tuple<Ts...> const &);
your class simply (?) become
template <typename ... Ts>
struct TheAnswer<std::variant<Ts...>>
{
using V1 = decltype(tuple2variant(std::declval<
decltype(std::tuple_cat( filterArithm<true, Ts>()... ))>()));
using V2 = decltype(tuple2variant(std::declval<
decltype(std::tuple_cat( filterArithm<false, Ts>()... ))>()));
};
If you want something more generic (if you want to pass std::arithmetic as a template parameter), you can modify the filterArithm() function passing a template-template filter parameter F (renamed filterType())
template <template <typename> class F, bool B, typename T>
constexpr std::enable_if_t<B == F<T>::value, std::tuple<T>>
filterType ();
template <template <typename> class F, bool B, typename T>
constexpr std::enable_if_t<B != F<T>::value, std::tuple<>>
filterType ();
The TheAnswer class become
template <typename, template <typename> class>
struct TheAnswer;
template <typename ... Ts, template <typename> class F>
struct TheAnswer<std::variant<Ts...>, F>
{
using V1 = decltype(tuple2variant(std::declval<decltype(
std::tuple_cat( filterType<F, true, Ts>()... ))>()));
using V2 = decltype(tuple2variant(std::declval<decltype(
std::tuple_cat( filterType<F, false, Ts>()... ))>()));
};
and the TA declaration take also std::is_arithmetic
using TA = TheAnswer<std::variant<bool, char, std::string, int, float,
double, std::vector<int>>,
std::is_arithmetic>;
The following is a full compiling example with std::is_arithmetic as parameter and a V2 empty case
#include <tuple>
#include <string>
#include <vector>
#include <variant>
#include <type_traits>
std::variant<std::monostate> tuple2variant (std::tuple<> const &);
template <typename ... Ts>
std::variant<Ts...> tuple2variant (std::tuple<Ts...> const &);
template <template <typename> class F, bool B, typename T>
constexpr std::enable_if_t<B == F<T>::value, std::tuple<T>>
filterType ();
template <template <typename> class F, bool B, typename T>
constexpr std::enable_if_t<B != F<T>::value, std::tuple<>>
filterType ();
template <typename, template <typename> class>
struct TheAnswer;
template <typename ... Ts, template <typename> class F>
struct TheAnswer<std::variant<Ts...>, F>
{
using V1 = decltype(tuple2variant(std::declval<decltype(
std::tuple_cat( filterType<F, true, Ts>()... ))>()));
using V2 = decltype(tuple2variant(std::declval<decltype(
std::tuple_cat( filterType<F, false, Ts>()... ))>()));
};
int main ()
{
using TA = TheAnswer<std::variant<bool, char, std::string, int, float,
double, std::vector<int>>,
std::is_arithmetic>;
using TB = TheAnswer<std::variant<bool, char, int, float, double>,
std::is_arithmetic>;
using VA1 = std::variant<bool, char, int, float, double>;
using VA2 = std::variant<std::string, std::vector<int>>;
using VB1 = VA1;
using VB2 = std::variant<std::monostate>;
static_assert( std::is_same_v<VA1, TA::V1> );
static_assert( std::is_same_v<VA2, TA::V2> );
static_assert( std::is_same_v<VB1, TB::V1> );
static_assert( std::is_same_v<VB2, TB::V2> );
}
This is a followup to this question.
I'm having a templated type with a template template argument
template <template <typename...> class CONTAINER, typename NUMBERTYPE>
struct spam {
template <class T>
using Temp = CONTAINER<T>;
};
I want to write a (templated) function that takes a spam instance and returns a spam instance of a slightly different type. I want to maintain the CONTAINER template parameter from the input and only specify the NUMBERTYPE. (godbolt link)
#include <type_traits>
#include <vector>
template <template <typename...> class CONTAINER, typename NUMBERTYPE>
struct spam {
template <class T>
using Temp = CONTAINER<T>;
};
template <typename T>
auto function(T in) {
spam<T::template Temp, double> retval;
return retval;
}
int main() {
spam<std::vector, float> one;
// spam<std::vector, double> two = function(one);
auto two = function(one);
return 0;
}
This mostly works, but I wanted to check if function() returns the type I expected by receiving the expected spam<std::vector, double> rather than accepting an auto return. The non-auto version does not compile because
<source>:18:45: error: conversion from 'spam<spam<std::vector, float>::Temp,[...]>' to non-scalar type 'spam<std::vector,[...]>' requested
spam<std::vector, double> two = function(one);
~~~~~~~~^~~~~
i.e. I have a mismatch between spam<std::vector, double> and spam<spam<std::vector, float>::template Temp, doulbe>, although I expect that spam<std::vector, float>::template Temp is the same as std::vector. (In fact I can check that std::is_same_v<spam<std::vector, float>::template Temp<int>, std::vector<int>> is indeed true - i.e. after providing the template arguments to Temp I have expected/desired behaviour, just that the code I'm contributing to works mostly with the unresolved CONTAINER).
QUESTION: is there a way to normalize T::template Temp to whatever it is and remove the spam<...>::Temp from the type?
QUESTION: is there a way to normalize T::template Temp to whatever it is and remove the spam<...>::Temp from the type?
No, as far I know.
But isn't necessary, in this case, because you can rewrite function() to intercept the template-template parameter CONTAINER.
I mean: you can rewrite function() as follows
template <template <typename...> class C, typename N>
spam<C, double> function (spam<C, N> const &)
{ return {}; }
The following is a full compiling example
#include <type_traits>
#include <vector>
template <template <typename...> class CONTAINER, typename NUMBERTYPE>
struct spam
{
template <typename T>
using Temp = CONTAINER<T>;
};
template <template <typename...> class C, typename N>
spam<C, double> function (spam<C, N> const &)
{ return {}; }
int main() {
spam<std::vector, float> one;
spam<std::vector, double> two = function(one);
auto three = function(one);
}
I need to implement a type converter in C++ to convert some type to another. For example, converting int16_t to float and int64_t to double. I have implemented one using template specialization:
template<class T>
struct TypeConverter
{
};
template<>
struct TypeConverter<int16_t>
{
using type = float;
};
template<>
struct TypeConverter<int64_t>
{
using type = double;
};
TEST(Exp, TypeConveter) {
static_assert(std::is_same_v<TypeConverter<int16_t>::type, float>);
static_assert(std::is_same_v<TypeConverter<int64_t>::type, double>);
}
Is there a better (more compact) way of achieving this using C++17 tmp features?
Another simple way (compatible with C++11):
template<class T> struct Type {};
float type_convert(Type<int16_t>);
double type_convert(Type<int64_t>);
int main() {
static_assert(std::is_same_v<decltype(type_convert(Type<int16_t>{})), float>);
static_assert(std::is_same_v<decltype(type_convert(Type<int64_t>{})), double>);
}
The benefit of this approach is that it uses argument-dependent name lookup (ADL) to find the corresponding type_convert function declaration (no definition necessary). If you need to handle user-defined types (UDT) it is easy to add corresponding overloads of type_convert for them in the same namespace where they are declared (without having to open the traits namespace to define another specialization of the trait class template for your UDT). E.g.:
namespace N {
struct MyType;
long double type_convert(Type<MyType>);
}
And then:
// type_convert is found by ADL.
static_assert(std::is_same_v<decltype(type_convert(Type<N::MyType>{})), long double>);
CE C++17 : https://gcc.godbolt.org/z/iY8Qoa
CE C++11 : https://gcc.godbolt.org/z/ApuxZj
User Code
#include<TypeMap.h>
#include<cstdlib>
using TMap = TypeMap <
std::pair<int16_t, float>,
std::pair<int64_t, double>
>;
void foo() {
static_assert(std::is_same_v<TMap::get<int16_t>, float>);
static_assert(std::is_same_v<TMap::get<int64_t>, double>);
static_assert(std::is_same_v<TMap::get<int>, NotFound>);
}
TypeMap.h
#include<type_traits>
#include<utility>
struct NotFound;
template<class... TPs>
struct TypeMap {
template<class T>
using get = NotFound;
};
template<class TP1, class... TPs>
struct TypeMap<TP1, TPs...> {
template<class T>
using get = std::conditional_t< std::is_same_v<T, typename TP1::first_type>
, typename TP1::second_type
, typename TypeMap<TPs...>::template get<T> >;
};
The most synthetic way I can imagine to register the types for a type converter is a couple of lists of types in a std::tuple (or something similar).
By example: if you want to convert std::int16_t to float, std::int32_t to double and std::int64_t to long double, you can using define the couple of types
using list1 = std::tuple<std::int16_t, std::int32_t, std::int64_t>;
using list2 = std::tuple<float, double, long double>;
Now, given the following struct and declared function
template <typename, typename, typename>
struct foo
{ using type = std::tuple<>; };
template <typename T1, typename T2>
struct foo<T1, T1, T2>
{ using type = std::tuple<T2>; };
template <typename T, typename ... Ts1, typename ... Ts2>
constexpr auto bar (std::tuple<Ts1...>, std::tuple<Ts2...>)
-> decltype( std::tuple_cat(
std::declval<typename foo<T, Ts1, Ts2>::type>()...) );
the TypeConverter become
template <typename T>
using TypeConverter
= std::tuple_element_t<0u, decltype(bar<T>(std::declval<list1>(),
std::declval<list2>()))>;
But I suppose that a couple of list in two different std::tuples is synthetic but difficult to understand and maintain.
So I propose a less synthetic (but more comprehensible and maintainable) way based on a single list of pair of types
using list = std::tuple<std::pair<std::int16_t, float>,
std::pair<std::int32_t, double>,
std::pair<std::int64_t, long double>>;
Now struct and declare function become
template <typename, typename>
struct foo
{ using type = std::tuple<>; };
template <typename T1, typename T2>
struct foo<T1, std::pair<T1, T2>>
{ using type = std::tuple<T2>; };
template <typename T, typename ... Ts>
constexpr auto bar (std::tuple<Ts...>)
-> decltype( std::tuple_cat(
std::declval<typename foo<T, Ts>::type>()...) );
and the TypeConverter
template <typename T>
using TypeConverter
= std::tuple_element_t<0u, decltype(bar<T>(std::declval<list>()))>;
The following is a full compiling C++17 example with both solutions (you can enable the first or the second changing the #if 0)
#include <tuple>
#include <type_traits>
#if 0
template <typename, typename, typename>
struct foo
{ using type = std::tuple<>; };
template <typename T1, typename T2>
struct foo<T1, T1, T2>
{ using type = std::tuple<T2>; };
template <typename T, typename ... Ts1, typename ... Ts2>
constexpr auto bar (std::tuple<Ts1...>, std::tuple<Ts2...>)
-> decltype( std::tuple_cat(
std::declval<typename foo<T, Ts1, Ts2>::type>()...) );
using list1 = std::tuple<std::int16_t, std::int32_t, std::int64_t>;
using list2 = std::tuple<float, double, long double>;
template <typename T>
using TypeConverter
= std::tuple_element_t<0u, decltype(bar<T>(std::declval<list1>(),
std::declval<list2>()))>;
#else
template <typename, typename>
struct foo
{ using type = std::tuple<>; };
template <typename T1, typename T2>
struct foo<T1, std::pair<T1, T2>>
{ using type = std::tuple<T2>; };
template <typename T, typename ... Ts>
constexpr auto bar (std::tuple<Ts...>)
-> decltype( std::tuple_cat(
std::declval<typename foo<T, Ts>::type>()...) );
using list = std::tuple<std::pair<std::int16_t, float>,
std::pair<std::int32_t, double>,
std::pair<std::int64_t, long double>>;
template <typename T>
using TypeConverter
= std::tuple_element_t<0u, decltype(bar<T>(std::declval<list>()))>;
#endif
int main ()
{
static_assert( std::is_same_v<float, TypeConverter<std::int16_t>> );
static_assert( std::is_same_v<double, TypeConverter<std::int32_t>> );
static_assert( std::is_same_v<long double, TypeConverter<std::int64_t>> );
}