I have a problem with variadic template templates:
template <typename T> class A { };
template< template <typename> class T> class B { };
template <template <typename> class T, typename parm> class C { typedef T<parm> type; };
template <typename... types> class D { };
template <template <typename...> class T, typename ... parms> class E { typedef T<parms...> type; };
// How to pass list in list??
template < template <typename...> class ...T, ???>
class F
{
};
First, pass a type to the template, no problem:
A<int> a; //ok
Now, I want to create an instance from B, but no way to pass the template template param:
B<A> b; // ok, but no chance to submit <int> inside A!
So I have to extend the parameter list:
C<A, int> c; // ok, this transport int as parm into A
Now I play with variadic templates in standard fashion:
D<> d1; // ok
D<int, float, double> d2; //ok
Passing parameters into the variadic part is also strait forward:
E<D> e1; //ok
E<D, double, float, int> e2; //ok
BUT: If I want to have a list of lists, I find no syntax which will me enable to pass
parameter lists to the list of types. What my intend is something like this. but also the above example shows that B<A<int>> b; is an error! So the following example couldn't work :-(
F< D< int, float>, D< int>, D <float, float, float> > f;
My target is to unroll the list of lists via template specialization. Any hints?
My solution after I understood the problem. Thanks!
Now I can unroll my variadic variadic template template as in the following example. The simple problem was, that I wait for a template class and not for a simple type. Sometimes, the solution can be so easy :-)
Thats my working result now:
template <typename ... > class D;
template <typename Head, typename... types>
class D<Head, types...>
{
public:
static void Do() { cout << "AnyType" << endl; D<types...>::Do(); }
};
template<>
class D<>
{
public:
static void Do() { cout << "End of D" << endl; }
};
template < typename ...T> class H;
template < typename Head, typename ...T>
class H<Head, T...>
{
public:
static void Do()
{
cout << "unroll H" << endl;
cout << "Subtype " << endl;
Head::Do();
H<T...>::Do();
}
};
template <>
class H<>
{
public:
static void Do() { cout << "End of H" << endl; }
};
int main()
{
H< D<int,int,int>, D<float, double, int> >::Do();
return 0;
}
You can unpack one variadic specialisation at a time through specialisation:
template<typename...> struct S;
template<> struct S<> { constexpr static int n = 0; };
template<template<typename...> class T, typename... Us, typename... Vs>
struct S<T<Us...>, Vs...> {
constexpr static int n = sizeof...(Us) + S<Vs...>::n;
};
template<typename...> struct D {};
#include <iostream>
int main() {
std::cout << S<D<int, int, int>, D<int, int>, D<int>>::n << '\n'; // prints 6
}
Like this :
template < template <typename...> class ...T >
class F
{
};
int main()
{
F< D, D > f;
}
So, what F is expecting is a variadic template class, that takes another variadic template class as it's argument.
You can not expand the arguments of the arguments of the template class argument. If you specialize the template class that you pass as argument, then you'll get the specialized version.
This :
F< D< int, float>, D< int>, D <float, float, float> > f;
doesn't work, since F expects variadic template class, taking variadic template classes as types, and D< int, float> is not a template anymore (it is a concrete class).
Related
This question is awful similar to How to tell if template type is an instance of a template class?
I would like to detect if a template parameter is from one particular template class that has no variadic template arguments.
template<class U, class S>
struct A{};
template<class T>
struct B {
B() {
if constexpr (T == A) {
// T is a template instantiation of `A`.
} else {
}
}
};
I can't change A's definition. I can change B's definition to have additional template parameters.
How do I implement (T == A) given the restriction of not knowing A's U and S?
I would go for a partial specialization here.
#include <iostream>
template<class U, class S>
struct A{};
template<class T>
struct B {
B() {
std::cout << "None-A implementation\n";
}
};
template<class U, class S>
struct B<A<U, S>> {
B() {
std::cout << "A implementation\n";
}
};
int main() {
B<int> b1;
B<A<int, int>> b2;
}
You have the option of leaving the default-case without an implementation.
Or you can have a fallback implementation for any none-A classes like here.
If the partial specialization forces too much code duplication you can also extract the detection part to it's own template variable like this.
#include <iostream>
template<class U, class S>
struct A{};
template <class T>
constexpr bool is_A_instatiation = false;
template <class U, class S>
constexpr bool is_A_instatiation<A<U, S>> = true;
template<class T>
struct B {
B() {
if constexpr (is_A_instatiation<T>) {
std::cout << "A instatiation!\n";
} else {
std::cout << "none-A instatiation!\n";
}
}
};
int main() {
B<int> b1;
B<A<int, int>> b2;
}
The easiest way is:
template<class T>
struct B{/*default implementation*/};
template<class U,class S>
struct B<A<U,S>>{/*Specified implementation*/};
A<T,U>: you already know it and search key
B<...>: variadic types which may include A<T,U> - known type
And you want to search A<T,U> in B<...>
template <typename T, typename U>
struct A {};
template <typename T, typename U, typename ...Ts>
struct B {
static constexpr bool value = ((std::is_same_v< A<T, U>, Ts> || ... ));
};
int main() {
std::cout << std::boolalpha <<
B<int,float, int, int, float, A<int,float>>::value << '\n'<<
B<int,float, int, int, float>::value <<std::endl;
}
Suppose I had a class that I wanted to declare with two "overloads", one that accepted 1 template parameter and another that accepted 2 like the pseudo code below:
template <typename I>
class B {
public:
};
template <typename F, typename I>
class B {
};
such that B can be instantiated with only 1 or 2 parameters:
B<int> hello;
B<int, int> hello2;
What is the correct way to do this?
Simple answer:
template <typename A, typename... Args> // ellipsis makes Args a
class B // template parameter pack
{
public:
};
int main()
{
B<int> hello;
B<int, int> hello2;
B<int, int, double> hello3;
}
Now Args is called a template parameter pack.
More specific to what you want:
template <typename F, typename I = int>
class B
{
public:
};
int main()
{
B<int> hello;
B<int, int> hello2;
}
This one allows a maximum of two template arguments.
When using template template arguments how can I have the template type of the template template deduced or erased?
Consider the following SSCCE:
#include <cstdint>
#include <cstddef>
#include <iostream>
using namespace std;
template<int i>
struct Value { };
template<int i>
struct BadValue { };
template<typename... G>
struct Print;
template<template<int> class ValueType, int... Is>
struct Print< ValueType<Is>... > {
static void print() {
const int is[] = { Is... };
for (int i: is)
cout << i;
cout << endl;
}
};
using V1 = Value<1>;
using V2 = Value<2>;
using V3 = Value<3>;
using BV = BadValue<1>;
int main() {
Print<V2, V1, V2, V3>::print(); // <-- fine
Print<V2, V1, V2, BV>::print(); // <-- BV used by accident
}
Deducing the template<int> class ValueType argument of the Print class to a template class like the Value and BadValue classes enforces that all the template arguments in the parameter pack to the Print class are specializations of the same ValueType template class - this is intentional. That is, the second line in the main() function causes a compile-time error as the ValueType argument cannot be deduced to match both the Value and BadValue classes. If the user by accident tries to mix the templates when using the Print template a compile time error arises, which provides a bit of diagnostic.
The above implementation, however, still has the int type fixed for the inner template argument of the ValueType template template argument. How can I erase it and have it deduced as well?
Generally speaking, when deducing a template template argument, how can I access the inner template argument?
If I understand correctly, you want that Print<V2, V1, V2, VB>::print(); generate an error that is simpler to understand.
For this, the best I can imagine is to works with static_assert()s.
In this particular case -- Print is a struct with only a partial specialization implemented and no general version implemented -- a not really but simple solution is available: implement the general version to give a static_assert() error with a message of your choice.
By example
template <typename ... G>
struct Print
{
static_assert( sizeof...(G) == 0, "not same int container for Print<>");
static void print()
{ };
};
template <template<int> class ValueType, int ... Is>
struct Print< ValueType<Is>... >
{
static void print()
{
using unused = int const [];
(void)unused { (std::cout << Is, 0)... };
std::cout << std::endl;
}
};
Unfortunately this solution accept as valid Print<>; I don't know if is good for you.
Another (better, IMHO, but more elaborate) solution can be transform the Print partial specialization in a specialization that accept variadic int containers (variadic ValueTypes instead a fixed ValueType) and, in a static_assert(), check (with a custom type traits) that all containers are the same.
Bye example, with the following custom type traits
template <template <int> class ...>
struct sameCnts : public std::false_type
{ };
template <template <int> class C0>
struct sameCnts<C0> : public std::true_type
{ };
template <template <int> class C0, template <int> class ... Cs>
struct sameCnts<C0, C0, Cs...> : public sameCnts<C0, Cs...>
{ };
you can write the Print specialization as follows
template <template <int> class ... Cs, int ... Is>
struct Print< Cs<Is>... >
{
static_assert(sameCnts<Cs...>{}, "different containers in Print<>");
static void print()
{
using unused = int const [];
(void)unused { (std::cout << Is, 0)... };
std::cout << std::endl;
}
};
If you can use C++17, you can use folding and the type traits can be written
template <template <int> class, template <int> class>
struct sameCnt : public std::false_type
{ };
template <template <int> class C>
struct sameCnt<C, C> : public std::true_type
{ };
template <template <int> class C0, template <int> class ... Cs>
struct sameCnts
: public std::bool_constant<(sameCnt<C0, Cs>::value && ...)>
{ };
and (using folding also in print() method) Print as follows
template <template <int> class ... Cs, int ... Is>
struct Print< Cs<Is>... >
{
static_assert( sameCnts<Cs...>{}, "different containers in Print<>");
static void print()
{ (std::cout << ... << Is) << std::endl; }
};
-- EDIT --
The OP ask
But how can I have the Print class accept also, for example, types that are specialized for a double non-type value instead of the int non-type values?
Not sure to understand what do you want but (remembering that a double value can't be a template non-type parameter) I suppose you want a Print that accept types with non-types template parameter when the type of this non type template parameter isn't fixed as in your example (int).
For C++11 and C++14 I think that in necessary to explicit the type of the non type values.
I mean... If you write Print as follows
template <typename ...>
struct Print;
template <typename T, template <T> class ... Cs, T ... Is>
struct Print< T, Cs<Is>... >
{
static_assert(sameCnts<Cs...>{}, "different containers in Print<>");
// ...
};
you have to use it this way
Print<int, V2, V1, V2, V3>::print();
that is explicating int (or long, or whatever) as first template parameter. This because the int type can't be deduced.
Starting from C++17 you can use auto as type for non-type template parameter, so you can write Print as follows
template <typename ...>
struct Print;
template <template <auto> class ... Cs, auto ... Is>
struct Print< Cs<Is>... >
{
static_assert( sameCnts<Cs...>{}, "different containers in Print<>");
static void print()
{ (std::cout << ... << Is) << std::endl; }
};
and the is no need to explicit the type and you can write
Print<V2, V1, V2, V3>::print();
In this case, you have to use auto instead of int also in sameCnt and sameCnts.
If you work in C++17, you can declare non-type template parameter with auto, so simply declare Is as auto..., and use auto instead of int in the function definition as possible as you can.
Of course, since type of elements of Is may be different, it may be impossible to declare the array is. Instead, you can use std::tuple and print the tuple instead.
// print_tuple is used to print a tuple
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp)>::type
print_tuple(const std::tuple<Tp...>&)
{ }
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp)>::type
print_tuple(const std::tuple<Tp...>& t)
{
std::cout << std::get<I>(t);
print_tuple<I + 1, Tp...>(t);
}
// ...
template<template<int> class ValueType, auto... Is>
// ^^^^
struct Print< ValueType<Is>... > {
static void print() {
print_tuple(std::make_tuple(Is...)); // make a tuple, and print it
}
};
LIVE EXAMPLE
The above pattern (making a tuple then dealing with the tuple) allows you to apply some complicated function to the parameter pack Is. However, if you only want to print the pack, you can alternatively use the C++17 feature fold expression instead, which is simpler.
template<template<int> class ValueType, auto... Is>
// ^^^^
struct Print< ValueType<Is>... > {
static void print() {
(std::cout << ... << Is); // fold expression, also C++17 feature
}
};
LIVE EXAMPLE
I have the following code, where I have a template class, and a type in it, which I would like to use in a separate template function.
template <typename... Types>
struct MyClass
{
enum SomeEnum { value0 = -1 };
};
template <typename... Types>
struct OtherClass
{
};
template <typename T, typename... Types>
T check(typename MyClass<Types...>::SomeEnum value)
{
OtherClass<Types...> obj;
T result;
// calculate result from obj;
return result;
}
int main() {
auto value = MyClass<int, bool>::value0;
// ...
int t = check<int>(value);
}
I tought that the compiler will be able to deduce the parameter pack from the function call, so I can use it in the function template also. Unfortunately the compiler can't deduce it:
$ g++ -std=c++11 op.cpp
op.cpp: In function ‘int main()’:
op.cpp:25:27: error: cannot convert ‘MyClass<int, bool>::SomeEnum’ to ‘MyClass<>::SomeEnum’ for argument ‘1’ to ‘T check(typename MyClass<Types ...>::SomeEnum) [with T = int; Types = {}; typename MyClass<Types ...>::SomeEnum = MyClass<>::SomeEnum]’
int t = check<int>(value);
Is there a solution to "transfer" the template parameter pack to the template function?
Template deduction is not possible, but maybe you can restructure your code in a way that MyClass defines the all necessary types and then you have a check function that takes MyClass as a template argument. That way, the checking function has access to all the necessary types.
template <typename... Types> struct OtherClass {};
template <typename... Types>
struct MyClass
{
typedef OtherClass<Types...> OtherClass_t;
typedef int result_t;
enum SomeEnum { value0 = -1 };
};
// version 1
template < typename C >
struct Checker {
typename C::result_t operator()(typename C::SomeEnum value)
{
typename C::OtherClass_t obj;
typename C::result_t result;
// calculate result from obj;
return result;
}
};
// version 2
template < typename C >
typename C::result_t check_fun(typename C::SomeEnum value)
{
typename C::OtherClass_t obj;
typename C::result_t result;
// calculate result from obj;
return result;
}
int main() {
typedef MyClass< int, bool > myclass_t;
auto value = myclass_t::value0;
// ...
Checker< myclass_t > check;
int t = check(value);
auto s = check_fun<myclass_t>(value);
}
The downside is of course, that you have to instantiate the checker class or call the function with the proper type of MyClass as template argument.
Template arguments cannot be deduced from nested types. This isn't new or changed with variadic templates.
The template parameter pack can be passed over using std::tuple. A wrapper class needed over SomeEnum type to store the parameter pack by creating a tuple type from them:
template <typename... Types>
struct MyClass
{
struct Value {
enum SomeEnum { value0 = -1 };
enum SomeEnum value;
typedef std::tuple<Types...> TypeTuple;
};
};
Than a helper class needed which feeds the template argument list of a template class from the tuple types:
template <
template <typename...> class Class,
typename Tuple, typename T, T... nums>
struct Helper_ : Class <
typename std::tuple_element<nums, Tuple>::type... >
{};
template <template <typename...> class Class, typename Tuple>
struct Helper : Helper_<
Class, Tuple,
make_integer_sequence<int, std::tuple_size<Tuple>::value > >
{};
The check function then uses this helper class to instanciate the other class:
template <typename T, typename V>
T check(V value)
{
Helper<OtherClass, typename V::TypeTuple> obj;
T result;
// calculate result from obj;
return result;
}
And the use of check function changes a bit becouse now it waits the wrapper type instead of the pure enum:
int main() {
MyClass<int, bool, double>::Value value;
value.value = MyClass<int, bool, double>::Value::value0;
int t = check<int>(value);
}
I have several classes with all the same template arguments. They use OftenUsedType which is also a template. So I typedef it to R to have more convenient notation:
template <class T, int A, int B>
class Obj{
typedef OftenUsedType<T, A, B> R;
}
Unfortunately, I have to do this in all classes which use OftenUsedType, since it depends on the template parameters.
The only way to make this a bit more convenient is to do the typedef in a class and inherit it to all classes which use it:
template <class T, int A, int B>
class ObjTypedef{
typedef OftenUsedType<T, A, B> R;
}
template <class T, int A, int B>
class Obj : public ObjTypedef<T, A, B>{
}
But I still have to inherit the typedef class into all classes which use the type...
Is there a more convenient, good-style way to do it?
If C++11 is acceptable, you could use an alias template, which has a much more natural syntax:
template <class T, int A, int B>
using R = OftenUsedType<T,A,B>;
The first thing I'd do is replace your int A and int B with
template<int I>
using int_t = std::integral_constant<int, I>;
so that all of your templates are types. You can get the value of the integer by constexpr constructing and using the constexpr operator().
template<class T>struct tag{using type=T;};
template<class Tag>using type=typename Tag::type;
template<template<class...>class Z, class T>
struct transcribe;
template<template<class...>class Z, template<class...>class T, class...Ts>
struct transcribe<Z,T<Ts...>>:tag<Z<Ts...>> {};
template<template<class...>class Z, class T>
using transcribe_t = type<transcribe<Z,T>>;
transcribe takes a template and an instance of some other template, and transcribes the arguments to the second instance's template into the first template, returning the result. We then leverage this in order to extract the arguments of the enclosing class, and create an OftenUsedType from it:
template<class T>
using often = transcribe_t< OftenUsedType, T >;
and now:
template<class T, class iA, class iB>
class Obj {
using R = often<Obj>;
};
will result in often<Obj> being OftenUsedType<T,iA,iB>. The using is optional -- you can just often<Obj> within Obj and get OftenUsedType<T,iA,iB>.
This can be done without converting all of your template arguments to classes. It just requires a different (and uglier) transcribe:
template<template<class, int, int>class Z, class T>
struct transcribe;
template<template<class, int, int>class Z,
template<class, int, int>class T,
class X, int A, int B>
struct transcribe<Z, T<X,A,B>>:tag<Z<X,A,B>> {};
template<template<class, int, int>class Z, class T>
using transcribe_t=type<transcribe<Z,T>>;
that has to be hand-coded for each pattern of type/scalars. Which makes me sad.
with a little boiler-template work, you can remove the need to repeat the <T, A, B>.
There are 2 methods here, one is to deduce the return type of a template function using decltype, the other is to simply use auto and use the template factory function to generate your often_used object.
#include <utility>
#include <string>
#include <iostream>
template<class T, int A, int B>
struct OftenUsedType
{
OftenUsedType()
: _mode { "none" }
{}
OftenUsedType(std::string mode)
: _mode { std::move(mode) }
{}
template<class I>
OftenUsedType(std::string mode, I i)
: _mode { mode + " " + std::to_string(i) }
{}
void frequent_method()
{
std::cout << "frequent method called with mode: " << _mode << " with " << T::name << " " << A << ", " << B << std::endl;
}
std::string _mode;
};
// deduces T, A and B from the type of the parameter passed
// and constructs the appropriate OftenUsedType
// with supplied paramters
template<template<typename, int, int> class Object, class T, int A, int B, class...Args>
OftenUsedType<T, A, B> make_often_used(const Object<T, A, B>&, Args&& ...args)
{
return OftenUsedType<T, A, B> { std::forward<Args>(args)... };
}
template <class T, int A, int B>
class Obj{
using R = decltype(make_often_used(std::declval<Obj>()));
// example of using R as a member
R _my_r;
public:
// example of using factor function based on argument deduction
void method()
{
auto often_used_object = make_often_used(*this);
often_used_object.frequent_method();
auto o2 = make_often_used(*this, "alpha");
o2.frequent_method();
auto o3 = make_often_used(*this, "alpha", 6);
o3.frequent_method();
}
private:
};
struct X {
static const std::string name;
};
const std::string X::name { "X" };
struct Y {
static const std::string name;
};
const std::string Y::name { "Y" };
int main()
{
Obj<X, 1, 2> x12;
Obj<Y, 6, 3> y63;
x12.method();
y63.method();
return 0;
}