I'm getting an "internal compiler error" with this using GCC 4.9.2:
#include <type_traits>
template <typename T, typename, int, template <typename U, U, U> class>
struct Sort;
template <typename T, template <T...> class Z, T N, T... Is,
template <typename U, U, U> class Comparator>
struct Sort<T, Z<N, Is...>, 0, Comparator> {
template <T I>
struct less_than : std::integral_constant<bool, Comparator<T, I, N>::value> {
};
};
int main() {}
The error message states:
c:\ADandD>g++ -std=c++14 ComparatorAndSorterTGeneralized.cpp
ComparatorAndSorterTGeneralized.cpp:254:80: internal compiler error: in tsubst,
at cp/pt.c:11738
template<T I>
struct less_than : std::integral_constant<bool, Comparator<T,I,N>::value> {};
^
Please submit a full bug report,
with preprocessed source if appropriate.
See http://gcc.gnu.org/bugs.html for instructions.
The issue is the template <typename U, U, U> class Comparator being used. I've never tried this before. At first I tried the template <typename T, T, T> class Comparator, but that would not compile because of the template shadowing, so I knew that was illegal. And then changing it to U still did not compile, so I thought the whole idea is not allowed.
Update: Upon instantiating, this compiles in Visual Studio 2015 Preview:
#include <type_traits>
template <typename T, typename, int, template <typename U, U, U> class>
struct Sort;
template <typename T, template <T...> class Z, T N, T... Is,
template <typename U, U, U> class Comparator>
struct Sort<T, Z<N, Is...>, 0, Comparator> {
template <T I>
struct less_than : std::integral_constant<bool, Comparator<T, I, N>::value> {
};
};
template <int...>
struct index_sequence {};
template <typename T, T A, T B>
struct LessThan : std::integral_constant < bool,
A<B> {};
enum { QuickSort, MergeSort, InsertionSort };
int main() {
Sort<int, index_sequence<4, 5, 6, 1, 2, 7>, QuickSort, LessThan> quickSort;
}
template <typename T, typename, int, template <typename U, U, U> class>
struct Sort;
This is perfectly legal.
It could be redeclared like this, giving names to all the parameters:
template <typename T, typename T2, int I, template <typename U, U X, U Y> class TT>
struct Sort;
It declares a class template Sort which has four template parameters, the type parameter T, a second type parameter T2 (unnamed in the original), a non-type template parameter I, and a template template parameter TT.
The template template parameter TT must a class template taking three template parameters, U is a type parameter and the second and third (X and Y) are non-type template parameters of type U.
A suitable argument for the fourth template parameter of Sort might be something like:
template <typename T, T t1, T t2>
class Foo
{ static const bool value = t1 < t2; };
which would be instantiated like:
Foo<int, 1, 2> fi;
or
Foo<char, 'a', 'b'> fc;
Related
If you have a template struct then you can use T as the type of a value parameter of a member template:
template <typename T>
struct SMoo
{
template <T I, typename T2>
struct SBaa {};
};
SMoo<int>::SBaa<3, bool> moobaa;
You can do the same with a variadic outer template:
template <typename ... VT>
struct SMoo
{
template <VT ... VI, typename T2>
struct SBaa {};
};
SMoo<int, bool>::SBaa<3, true, bool> moobaa;
You can also use T as the type of a value parameter of a template-template parameter of a member template:
template <typename T>
struct SMoo
{
template <template <T I, typename T2> typename TT>
struct SBaa {};
};
template <int I, typename T>
struct SCaw {};
SMoo<int>::SBaa<SCaw> moobaacaw;
You can combine these to get:
template <typename ... VT>
struct SMoo
{
template <template <VT ... VI, typename T2> typename TT>
struct SBaa {};
};
template <int I, typename T>
struct SCaw {};
SMoo<int>::SBaa<SCaw> moobaacaw;
But this seems to fail as soon as there's more than one VT parameter:
template <typename ... VT>
struct SMoo
{
template <template <VT ... VI, typename T2> typename TT>
struct SBaa {};
};
template <int I, typename VT>
struct SCaw {};
template <int I, bool B, typename VT>
struct SMew {};
SMoo<int>::SBaa<SCaw> moobaacaw;
//SMoo<int, bool>::SBaa<SMew> moobaamew; // <<=== FAILS HERE (WHY?)
SMoo<int, bool>::SBaa<SCaw> moobaacaw2; // <<=== ALSO, DOESN'T FAIL HERE (WHY?)
the error is:
<FILE>:5:27: error: type/value mismatch at argument 1 in template parameter list for ‘template<class ... VT> template<template<template<VT ...VI, class T2> class TT> template<class ... VT> template<VT ...VI, class T2> class TT> struct SMoo<VT>::SBaa’
15 | SMoo<int, bool>::SBaa<SMew> moobaamew; // <<=== FAILS HERE (WHY?)
| ^
<FILE>:15:27: note: expected a template of type ‘template<class ... VT> template<VT ...VI, class T2> class TT’, got ‘template<int I, bool B, class VT> struct SMew’
It's like the VT parameter isn't being matched accurately.
Can this be fixed?
Given this template function:
template <
typename T,
typename U,
typename = std::enable_if<
std::is_same_v<U, std::unique_ptr<T>> ||
std::is_same_v<U, std::shared_ptr<T>>>>
T foo(U val) {
if constexpr (std::is_same_v<U, std::unique_ptr<T>>) {
return *val;
}
return *val;
}
I want to call it like this:
int x = foo(std::make_unique<int>(1));
But, it's giving this error:
Candidate template ignored: couldn't infer template argument 'T'
I can fix it by providing the type T explicitly:
int x = foo<int>(std::make_unique<int>(1));
Is it possible to fix it such that it can infer? The type is clearly embedded in the typename U but it does not seem to "propagate" to T.
SFINAE constraints don't affect template argument deduction. Your compiler has to deduce T and U first, without even looking at your enable_if_t<...>.
I'd do something like this:
#include <memory>
#include <type_traits>
namespace impl
{
template <typename A, template <typename...> typename B>
struct specialization_of : std::false_type {};
template <template <typename...> typename T, typename ...P>
struct specialization_of<T<P...>, T> : std::true_type {};
}
template <typename A, template <typename...> typename B>
concept specialization_of = impl::specialization_of<A, B>::value;
template <typename T>
requires specialization_of<T, std::unique_ptr> || specialization_of<T, std::shared_ptr>
auto foo(T val)
{
if constexpr (specialization_of<T, std::unique_ptr>)
{
return *val;
}
return *val;
}
[I also want] std::is_same_v<U, std::function<T()>>
Then you need a specialized template just for this task. Something like:
template <typename T, typename U>
struct foo : std::false_type {};
template <typename T, typename U>
struct foo<std::function<T()>, U> : std::is_same<T, U> {};
Then foo<std::function<int()>, int> is true.
Consider this fully working code:
#include <type_traits>
template <typename T, typename IndexPack> struct Make;
template <typename T, template <T...> class P, T... Indices>
struct Make<T, P<Indices...>> {
using type = P<(Indices+1)..., (-3*Indices)..., (Indices-1)...>;
};
template <int...> class Pack;
int main() {
static_assert (std::is_same<Make<int, Pack<1,2,3,4>>::type,
Pack<2,3,4,5, -3,-6,-9,-12, 0,1,2,3>>::value, "false");
}
What I actually want the output to be is
Pack<2,-3,0, 3,-6,1, 4,-9,2, 5,-12,3>
instead of Pack<2,3,4,5, -3,-6,-9,-12, 0,1,2,3>. I first tried
using type = P<(Indices+1, -3*Indices, Indices-1)...>;
but that is simply understood by the compiler to be a useless comma operator. What is the desired syntax to get what I want? If there is no such syntax, what is the cleanest way to do this, keeping in mind that using Indices 3 times is just an example (we may want to use it more than 3 times). Please don't tell me that I have to write a helper to extract the individual packs and then "interlace" all the elements. That nightmarish method cannot be the best solution (and such a solution would also only work if we knew exactly how many individual packs to extract).
Would defining
template <typename T, template <T...> class P, T I>
struct Component {
using type = P<I+1, -3*I, I-1>;
};
help somehow? Make a pack expansion on this?
Yes, you can concat recursively:
template <typename, typename, typename> struct Concat;
template <typename T, template <T...> class P, T... A, T... B>
struct Concat<T, P<A...>, P<B...>> {
using type = P<A..., B...>;
};
template <typename T, typename IndexPack> struct Make;
template <typename T, template <T...> class P, T... I, T F >
struct Make<T, P<F, I...>> {
using type = typename Concat<T,
typename Make<T, P<F>>::type,
typename Make<T, P<I...>>::type>::type;
};
template <typename T, template <T...> class P, T I>
struct Make<T, P<I>> {
using type = P<I+1, -3*I, I-1>;
};
Demo
This was inspired by Columbo's solution. It uses the pack expansion syntax that I originally sought, namely
using type = typename Merge<T, typename Component<T, P, Indices>::type...>::type;
As a result, now Make is reusable, first using Triple, and then using Quadruple, so any number of usages of Indices can be expanded simultaneously. Here Component is a template-template-template parameter passed into Make:
#include <type_traits>
template <typename T, typename... Packs> struct Merge;
template <typename T, template <T...> class P1, template <T...> class P2, T... Is, T... Js>
struct Merge<T, P1<Is...>, P2<Js...>> {
using type = P1<Is..., Js...>;
};
template <typename T, typename Pack1, typename Pack2, typename... Packs>
struct Merge<T, Pack1, Pack2, Packs...> {
using type = typename Merge<T, Pack1, typename Merge<T, Pack2, Packs...>::type>::type;
};
template <typename T, template <T...> class P, T I>
struct Triple {
using type = P<I+1, -3*I, I-1>;
};
template <typename T, template <T...> class P, T I>
struct Quadruple {
using type = P<I+1, -3*I, I-1, I>;
};
template <typename T, typename IndexPack,
template <typename U, template <U...> class P, U I> class Component> struct Make;
template <typename T, template <T...> class Z, T... Indices,
template <typename U, template <U...> class P, U I> class Component>
struct Make<T, Z<Indices...>, Component> {
using type = typename Merge<T, typename Component<T, Z, Indices>::type...>::type;
};
template <int...> class Pack;
int main() {
static_assert (std::is_same<Make<int, Pack<1,2,3,4>, Triple>::type,
Pack<2,-3,0, 3,-6,1, 4,-9,2, 5,-12,3>>::value, "false");
static_assert (std::is_same<Make<int, Pack<1,2,3,4>, Quadruple>::type,
Pack<2,-3,0,1, 3,-6,1,2, 4,-9,2,3, 5,-12,3,4>>::value, "false");
}
I have a type trait that checks if a given type is an instance of a given class template:
template <template <typename...> class C, typename T>
struct check_is_instance_of : std::false_type { };
template <template <typename...> class C, typename ...Ts>
struct check_is_instance_of<C, C<Ts...>> : std::true_type { };
template <template <typename...> class C, typename T>
struct is_instance_of : check_is_instance_of<C, std::remove_cv_t<T>> { };
Unfortunately, this does not work for non-type template parameters as they are not "captured" by the variadic template parameters, so
is_instance_of<std::integral_constant, std::true_type>
yields a compile-error. Is there any way to write an implementation of is_instance_of that works for an arbitrary number of type and non-type template parameters?
I don't think there is a clean way to do this unless the non-type arguments are all of the same type and you know which type it is. In that very specific case, function overloading can be used.
In any other case, you end up in a template-argument version of the perfect forwarding problem where you would have to specialize for every type/nontype argument combination.
If you only need to address homogeneous non-template arguments and you can guess the type, the following should work. You can overload instance_of for different types (only int is covered here), but you'd have to explicitly create an instance for each type you want to be able to handle:
// variation for non-type parameters, only for uniform parameters with
// known type.
template <typename V, template <V...> class C, typename T>
struct check_is_instance_of_nontype : std::false_type { };
template <typename V, template <V...> class C, V... Values>
struct check_is_instance_of_nontype<V, C, C<Values...>> : std::true_type { };
// this is as in your example
template <template <typename...> class C, typename T>
struct check_is_instance_of : std::false_type { };
template <template <typename...> class C, typename ...Ts>
struct check_is_instance_of<C, C<Ts...>> : std::true_type { };
template <template <typename...> class C, typename T>
struct is_instance_of : check_is_instance_of<C, std::remove_cv_t<T>> { };
template <template <typename...> class C, typename T>
constexpr bool instance_of()
{
return is_instance_of< C, T>::value;
}
template <template <int...> class C, typename T>
constexpr bool instance_of()
{
return check_is_instance_of_nontype< int, C, T>::value;
}
template< int... >
struct Duck
{
};
template<typename A, typename B>
struct Swallow
{
};
int main() {
typedef Duck<1, 2> SittingDuck;
typedef Swallow< int, int> UnladenSwallow;
std::cout << instance_of< Duck, SittingDuck>() << instance_of< Swallow, UnladenSwallow>();
return 0;
}
Suppose you have something like
template <typename, typename, int, typename, int, typename...> struct P
and you want to reverse the typename... part only. Now you've already written the generic reverse transformation:
// Reverse<Pack<Types...>>::type is Pack<Types'...>, where Types'... is Types... reversed.
template <typename, typename> struct ReverseHelper;
template <template <typename...> class P, typename Pack>
struct ReverseHelper<P<>, Pack> {
using type = Pack;
};
template <template <typename...> class P, typename First, typename... Rest, typename... Types>
struct ReverseHelper<P<First, Rest...>, P<Types...>> : ReverseHelper<P<Rest...>, P<First, Types...>> {};
template <typename> struct Reverse;
template <template <typename...> class P, typename... Types>
struct Reverse<P<Types...>> : ReverseHelper<P<Types...>, P<>> {};
Of course, we could rewrite the above with template <typename, typename, int, typename, int, typename...> class P instead, namely:
template <typename, typename> struct ReverseHelper1;
template <template <typename, typename, int, typename, int, typename...> class P,
typename U, typename V, int M, typename W, int N, typename Pack>
struct ReverseHelper1<P<U,V,M,W,N>, Pack> {
using type = Pack;
};
template <template <typename, typename, int, typename, int, typename...> class P,
typename U, typename V, int M, typename W, int N, typename First, typename... Rest, typename... Types>
struct ReverseHelper1<P<U,V,M,W,N, First, Rest...>, P<Types...>> : ReverseHelper<P<U,V,M,W,N, Rest...>, P<First, Types...>> {};
template <typename> struct Reverse1;
template <template <typename, typename, int, typename, int, typename...> class P,
typename U, typename V, int M, typename W, int N, typename... Types>
struct Reverse1<P<U,V,M,W,N, Types...>> : ReverseHelper1<P<U,V,M,W,N, Types...>, P<U,V,M,W,N>> {};
Notice we are just repeating? And then we would have to do this again and again for other template signatures if we want to do the same partial reversal thing. So how to make the approach by using the original Reverse itself to avoid all this repetition?
For example, let's suppose we have
template <typename> struct Foo;
template <typename> struct Bar;
template <template <typename, typename, int, typename, int, typename...> class P,
typename U, typename V, int M, typename W, int N, typename... Args>
struct Foo<P<U,V,M,W,N, Args...>> {};
Let's have Foo<P<U,V,M,W,N, Args...>> derive from Bar<P<U,V,M,W,N, ArgsReversed...>>. How to accomplish this using the defined Reverse from above?
Note, it's not the same thing as
template <template <typename, typename, int, typename, int, typename> class P,
typename U, typename V, int M, typename W, int N,
template <typename...> class Q, typename... Args>
struct Foo<P<U,V,M,W,N, Q<Args...>>> : Bar<P<U,V,M,W,N, typename Reverse<Q<Args...>>::type>> {};
though I suspect accomplishing it is done something along the lines of this. Of course, reversing is just an example. We want to reuse any transformation to make the same transformation for only part of (any) larger template structure.
The easy way is to stop using int as arguments to templates.
Barring that, you can write metafunctions for a particular pattern of class and int types, and "lift" both the template and the instance to being about classes (where int is replaced with integral_constant), and operate on those (write "reverse types after N types" to get the reverse done).
Barring that, we can hand code for your particular pattern.
template<class...>struct types{using type=types;};
namespace details {
template<class T, class types>
struct replace_tail;
template<class T, class types>
using replace_tail_t = typename replace_tail<T,types>::type;
template<class T>
struct get_tail;
template<class T>
using get_tail_t = typename get_tail<T,types>::type;
template<template <class, class, int, class, int, class...> class P,
class A, class B, int C, class D, int E, class...Fs,
class... Ts
>
struct replace_tail<P<A,B,C,D,E,Fs...>,types<Ts...>> {
using type = P<A,B,C,D,E,Ts...>;
};
template<template <class, class, int, class, int, class...> class P,
class A, class B, int C, class D, int E, class...Fs
>
struct get_tail<P<A,B,C,D,E,Fs...>>:types<Fs...>{};
template<class T>
using reverse_t = ReverseHelper<T>::type;
template<class T>
using reverse_tail = replace_tail_t < T, reverse_t<get_tail_t<T>> >;
}
using details::reverse_tail;
which may contain syntax errors. The plan is to break it into 3 parts.
First, reversing a pack (you wrote this already).
Second, extracting the "tail" arguments to reverse from an instance into a pack.
Third, replacing the "tail" arguments with another pack.
Hooked together, we reverse the tail. As a specializing get_tail_t and replace_tail_t for a new pattern of template arguments will make reverse_tail_t "just work".
Let's make a typelist:
template <typename...> struct typelist { };
You can get the N-th type of the typelist:
template <size_t N, typename> struct typelist_get;
template <typename T, typename ...Ts>
struct typelist_get<0, typelist<T, Ts...>>
{
using type = T;
};
template <size_t N, typename T, typename ...Ts>
struct typelist_get<N, typelist<T, Ts...>>
: typelist_get<N - 1, typelist<Ts...>>
{ };
You can reverse a typelist:
template <typename, typename> struct reverse_helper;
template <typename T, typename ...Ts, typename ...Rs>
struct reverse_helper<typelist<T, Ts...>, typelist<Rs...>>
: reverse_helper<typelist<Ts...>, typelist<T, Rs...>>
{ };
template <typename ...Rs>
struct reverse_helper<typelist<>, typelist<Rs...>>
{
using type = typelist<Rs...>;
};
template <typename T> struct typelist_reverse
: reverse_helper<T, typelist<>>
{ };
We also need a index_sequence:
template <size_t...> struct index_sequence;
and a way to build an index_sequence<0, 1, ..., N - 1> for given N:
template <std::size_t N, std::size_t ...I>
struct index_sequence_builder
{
using type = typename index_sequence_builder<N - 1, N - 1, I...>::type;
};
template <std::size_t ... I>
struct index_sequence_builder<0, I...>
{
using type = index_sequence<I...>;
};
template <std::size_t N>
using make_index_sequence = typename index_sequence_builder<N>::type;
Let's say we have some variadic template class Foo:
template <typename ...Ts> struct Foo { };
Then we can reverse it as follows:
template <typename, typename> struct reverse_foo_impl;
template <typename ...Ts, size_t ...I>
struct reverse_foo_impl<Foo<Ts...>, index_sequence<I...>>
{
using TL = typelist<Ts...>;
using RTL = typename typelist_reverse<TL>::type;
using type = Foo<typename typelist_get<I, RTL>::type...>;
};
template <typename> struct reverse_foo;
template <typename...Ts>
struct reverse_foo<Foo<Ts...>>
: reverse_foo_impl<Foo<Ts...>, make_index_sequence<sizeof...(Ts)>>
{ };
Here, TL are the template parameters of Foo as typelist, RTL is the same typelist reversed. To extract the template parameters as pack, we need to create something like typelist_get<0, RTL>::type, typelist_get<1, RTL>::type, ..., typelist_get<N - 1, RTL>::type. This is accomplished using the index sequence where the expansion w.r.t. I exactly recreates that pattern.
In the end we can use it like this:
using T = Foo<int, char, double>;
using R = reverse_foo<T>::type;
static_assert(std::is_same<Foo<double, char, int>, R>::value, ":(");