Template default argument - c++

How do I specify a template class as a default value for a template typename? e.g. the following doesn't work.
template <typename A, typename B> class X {};
template <typename T=template <typename, typename> class X> class Y {};
int main()
{
Y<> y;
return 0;
}
tmp.cc:4:22: error: expected type-specifier before ‘template’
template <typename T=template <typename, typename> class X> class Y {};
^~~~~~~~
tmp.cc:4:22: error: expected ‘>’ before ‘template’
tmp.cc: In function ‘int main()’:
tmp.cc:8:7: error: template argument 1 is invalid
Y<> y;
^

The problem of your code is that for Y you ask a type template parameter and you want to use a template template parameter.
template <typename A, typename B> class X {};
// type template template
//........VVVVVVVVVV VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
template <typename T=template <typename, typename> class X> class Y {};
int main()
{
Y<> y;
return 0;
}
If you want to use X as default, T must be be a template template, so
template <typename, typename>
class X
{};
template <template <typename, typename> class T = X>
class Y
{};
int main ()
{
Y<> y;
}
Or also using variadics to improve flexibility
template <template <typename...> class T = X>
class Y
{};

Related

How to check if an object is an instance of a template class of multiple template arguments in C++?

I have the following class:
template <typename T, typename U = UDefault>
class A;
How to check whether types such as A<float> or A<float, int> are instances of the above templated class?
I tried modifying How to check if an object is an instance of a template class in C++? into:
template <typename T, typename U>
struct IsA : std::false_type
{};
template <typename T, typename U>
struct IsA<A<T, U>> : std::true_type
{};
but it's giving the following error
20:18: error: wrong number of template arguments (1, should be 2)
16:8: error: provided for 'template<class T, class U> struct IsA'
In function 'int main()':
40:34: error: wrong number of template arguments (1, should be 2)
16:8: error: provided for 'template<class T, class U> struct IsA'
How can this be solved?
Your IsA class should be expected to take one template argument. The type you are testing.
template <typename Type>
struct IsA : std::false_type {};
template <typename T, typename U>
struct IsA< A<T,U> > : std::true_type {};
// ^^^^^^ The specialization of your one template argument.
Or put alternately, since the individual template parameters to A do not matter here:
template <typename ...AParams>
struct IsA< A<AParams...> > : std::true_type {};
// ^^^^^^^^^^^^^ The specialization of your one template argument.
See it work in Compiler Explorer

Using CRTP with partial class specialization?

I'm trying to mix-in an operator [] with a class. My problem is I've partially specialized the class, and the compiler doesn't like me not specifying the template parameters to the derived class:
#include <iostream>
#include <type_traits>
using namespace std;
template <typename T>
struct mixin {
template <typename U>
void operator[](U u) {
cout << u;
}
};
template <typename T, typename = void>
struct derived : mixin<derived> {};
template <typename T>
struct derived<T,
typename enable_if<
is_same<T, int>{}
>::type> : mixin<derived> {};
int main() {
derived<int> d;
d[3.14];
}
With clang this gives:
test.cc:16:24: error: use of class template 'derived' requires template arguments
struct derived : mixin<derived> {};
^~~~~~~
test.cc:16:8: note: template is declared here
struct derived : mixin<derived> {};
^
test.cc:23:22: error: use of class template 'derived' requires template arguments
>::type> : mixin<derived> {};
^~~~~~~
test.cc:16:8: note: template is declared here
struct derived : mixin<derived> {};
^
gcc is even less helpful:
test.cc:16:31: error: type/value mismatch at argument 1 in template parameter list for ‘template<class T> struct mixin’
struct derived : mixin<derived> {};
^
test.cc:16:31: note: expected a type, got ‘derived’
test.cc:23:29: error: type/value mismatch at argument 1 in template parameter list for ‘template<class T> struct mixin’
>::type> : mixin<derived> {};
^
test.cc:23:29: note: expected a type, got ‘derived’
test.cc: In function ‘int main()’:
Is my only option to re-specify the template parameters inside of the mixin clause?
Well, try this:
#include <iostream>
#include <type_traits>
using namespace std;
template <typename T>
struct mixin {
template <typename U>
void operator[](U u) {
cout << u;
}
};
template <typename T, typename = void>
struct derived : mixin<derived<T>> {};
template <typename T>
struct derived<T,
typename enable_if<
is_same<T, int>::value
>::type> : mixin<derived<T>> {};
int main() {
derived<int> d;
d[3.14];
}
It does work...
What I changed:
Using is_same<foo,bar>::value, not is_same<foo,bar>{} edit: Hmm, it seems you don't need to change that after all. Neat!
Not trying to get the compiler to deduce the template parameter for derived when using mixin<derived>. You were being way too optimistic there...

hana types for template-of-templates

I am trying to generate a type that is using template-of-templates using boost::hana but ran into trouble.
I have the following classes
template<template<typename> typename BarModel>
struct Foo {
BarModel<double> bar;
}
template<typename T>
struct BarOne {
T x;
}
template<typename T>
struct BarTwo {
T y;
}
I now want to create a Foo<BarImpl> for each of the BarX<T> classes:
auto bar_types = hana::tuple_t<hana::template_t<BarOne>, hana::template_t<BarTwo>>;
hana::for_each(bar_types, [](auto t) {
auto footype = SOMETHING(t);
});
Problem, is I am not sure how this is supposed to be done.
My first attempt was to do
using BarT = typename decltype(t)::type;
auto bar_t = BarT(); // template_t, can create BarX<T> classes
auto foo_t = hana::template_<Foo>; // <-- FAIL
auto foo_bar_t = foo_t(bar_t);
but this fails with a
error: type/value mismatch at argument 1 in template parameter list for ‘template<template<class ...> class F> constexpr const boost::hana::template_t<F> boost::hana::template_<F>’
note: expected a template of type ‘template<class ...> class F’, got ‘template<template<class> class BarModel> class Foo’
The note suggests that hana::template_ does not work with template-of-templates.
Is this the case? If so, is there an alternative solution?
Boost.Hana does not support this directly, but implementing it for this case is just a few lines of code.
Check it out:
#include <boost/hana.hpp>
namespace hana = boost::hana;
template <template <template <typename...> class> class F>
struct template_template_t
{
template <template <typename...> class G>
constexpr auto operator()(hana::basic_type<hana::template_t<G>>) const
-> hana::type<F<G>>
{ return {}; }
};
template <template <template <typename...> class> class F>
constexpr auto template_template = template_template_t<F>{};
/*****/
template <template <typename...> class BarModel>
struct Foo {
BarModel<double> bar;
};
template <typename T>
struct BarOne {
T x;
};
template <typename T>
struct BarTwo {
T y;
};
int main() {
constexpr auto bar_types = hana::tuple_t<hana::template_t<BarOne>, hana::template_t<BarTwo>>;
BOOST_HANA_CONSTANT_ASSERT(hana::equal(
hana::transform(bar_types, template_template<Foo>)
, hana::tuple_t<Foo<BarOne>, Foo<BarTwo>>
));
}

how to get template parameter of a template template parameter?

Assume std::vector didnt have a value_type. Is is possible to write a template to deduce the value_type? Or more general, given a T<X>, how can I deduce X?
A very naive..
template <template <typename X> T>
void test(T<X> t) {
X x;
}
will probably make anybody who knows a bit about templates laugh at my foolish attempt and when instantiated like this:
int main() {
std::vector<int> x;
test(x);
}
create the following errors:
error: expected ‘class’ before ‘T’
template < template<typename X> T>
^
error: ‘X’ was not declared in this scope
void test(T<X> u) {
^
error: template argument 1 is invalid
void test(T<X> u) {
^
In function ‘void test(int)’:
error: ‘X’ was not declared in this scope
X x;
^
error: expected ‘;’ before ‘x’
X x;
^
In function ‘int main()’:
error: no matching function for call to ‘test(std::vector<int>&)’
test(x);
^
note: candidate is:
note: template<template<class X> class T> void test(int)
void test(T<X> u) {
^
note: template argument deduction/substitution failed:
note: cannot convert ‘x’ (type ‘std::vector<int>’) to type ‘int’
EDIT: the first one is easy to fix, but fixing it wont affect the others...
PS: I think I have a small misunderstanding, as std::vector<int> isnt a template, but a concrete type. However, still I would like to know if there is a way to get the int from a someTemplate<int> with some template magic.
You can create a traits to extract those parameter:
template <typename T> struct first_param;
template <template <typename, typename...> class C, typename T, typename ...Ts>
struct first_param<C<T, Ts...>>
{
using type = T;
};
For pre C++11, you have to handle number of parameters until acceptable values:
template <typename T> struct first_param;
template <template <typename> class C, typename T>
struct first_param<C<T>>
{
typedef T type;
};
template <template <typename, typename> class C, typename T, typename T2>
struct first_param<C<T, T2>>
{
typedef T type;
};
template <template <typename, typename, typename> class C,
typename T, typename T2, typename T3>
struct first_param<C<T, T2, T3>>
{
typedef T type;
};
// ...

Deduce template parameter's template parameter

There is a class template A, which is taking template class for its template parameter.
template <typename T> class A {}
template <typename T> class B {}
int main()
{
A<B<int>>();
return 0;
}
Can class template A deduces its template parameter(B int)'s template parameter(int)?
Or is there the other way to solve this problem? For example,
template <typename T<typename U>> class A {}
You can make A a template template:
template <template <typename> class T, typename Inner>
class A<T<Inner>> {};
template<class>struct inner{};
template<template<class...>class Z, class T, class...Ts>
struct inner<Z<T, Ts...>>{
using type=T;
};
template<class Z>
using inner_t=typename inner<Z>::type;
and inner_t<X> is the first template argument of X if it exists, and a substitution failure otherwise.
What you described is a template template:
template< template<typename> class T > class A {};
note the class before T has to be class, not typename.