How can I specialize this template class? - c++

Suppose I have a class
template<template<typename, std::size_t> class Child, typename T, std::size_t D>
class tuple;
How can I specialize this for D = 2 with a Child type which has only one typename template argument?
I've tried
template<template<typename> class Child>
struct foo
{
template<typename U, typename V>
using type = Child<U>;
};
template<template<typename> class Child, typename T>
class tuple<typename foo<Child>::type, T, 2>;
by the compiler says that the template argument Child is not deducible ...

with a Child type which has only one typename template argument?
You can't. Your original template requires a template template parameter with two template parameters, one a type parameter and the other a non-type parameter. A template that can take only one parameter does not match that (and neither would template<typename U, typename V> which takes two type template parameters).
Trying to indirect through an alias template member in a class also can't work, because nested names are non-deduced contexts.
(Also Child is not a type, it is a template.)

Related

Deducing variadic member type from types of arguments passed to constructor

I'm trying to deduce the type of a member variable from the types of arguments passed to its class' constructor. The constructor of the class (a PublishSubscribe class) receives two parameters, each representing variadic types (one variadic pack for sending, one for receiving).
The code I'm trying to get working is the following:
#include <tuple>
template <typename... Types>
struct TopicTypes {};
TopicTypes<int> type_subscribe_topics;
TopicTypes<int,double> type_publish_topics;
template <typename... TReceives>
class PublishSubscribe
{
public:
template < typename... TReceives, template <typename...> class TR,
typename... TSends, template <typename...> class TS>
PublishSubscribe(const TR<TReceives...>&,
const TS<TSends...>&){}
private:
std::tuple<TReceives...> member_;
};
class UserClass : public PublishSubscribe{
public:
UserClass()
: PublishSubscribe(
type_subscribe_topics,
type_publish_topics
){}
};
int main()
{
return 0;
}
I'm getting the following compilation error:
variadic3.cpp:13:17: error: declaration of 'class ... TReceives'
template < typename... TReceives, template <typename...> class TR,
^
variadic3.cpp:9:11: error: shadows template parm 'class ... TReceives'
template <typename ... TReceives>
How would one template the PublishSubscribe class with the types of type_subscribe_topics? I would require PublishSubscribe<magic(decltype(type_subscribe_topics))> which would default to PublishSubscribe<int> in this particular case..
Many thanks in advance!
You cannot use the same template name in a class template and member function template. You have
template <typename... TReceives>
class PublishSubscribe
and
template < typename... TReceives, template <typename...> class TR,
typename... TSends, template <typename...> class TS>
PublishSubscribe(const TR<TReceives...>&,
const TS<TSends...>&){}
Which both use TReceives. You either need to change the name in one of the templates or, if you are using the TReceives that you passed to the class you can just get rid of it from the function which would look like
template < template <typename...> class TR,
typename... TSends, template <typename...> class TS>
PublishSubscribe(const TR<TReceives...>&,
const TS<TSends...>&){}
You are not going to be able to use the template parameters of the constructor to define the types the the member_ tuple should use. You could make the class less general and just take a tuple like
template <typename T>
class PublishSubscribe
and then you would use it like
PublishSubscribe<decltype(some_tuple)> foo(some_tuple, some_other_tuple);
and member_ would just become T member_;

Template specialization for fundamental types

Is there any way to make a template specialization for fundamental types only?
I have tried to do the following:
template<typename T, typename = typename std::enable_if<!std::is_fundamental<T>::value>::type>
class foo
{
}
template<typename T, typename = typename std::enable_if<std::is_fundamental<T>::value>::type>
class foo
{
}
But I'm getting an error that the template is already defined.
Here you are creating two templated classes with the same name, not specializations.
You need to create a generic one and then specialize it:
// not specialized template (for non-fundamental types), Enabler will
// be used to specialize for fundamental types
template <class T, class Enabler = void>
class foo { };
// specialization for fundamental types
template <class T>
class foo<T, std::enable_if_t<std::is_fundamental<T>::value>> { };

Template specialization with non-empty template parameter list

I have difficulties to understand the following code
template <typename T>
struct function_traits
: public function_traits<decltype(&T::operator())>
{};
// For generic types, directly use the result of the signature of its 'operator()'
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
// we specialize for pointers to member function
{
// ...
}
int main()
{
auto lambda = [](int i) { return long(i*10); };
typedef function_traits<decltype(lambda)> traits;
// ...
return 0;
}
which occurs in the answer https://stackoverflow.com/a/7943765/7006673.
Here,
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
seems to indicate a specialization of the template class
template <typename T>
struct function_traits
however, the template parameter list of the specialization template <typename ClassType, typename ReturnType, typename... Args> is not empty (i.e., is not equal to template <>).
Can someone please help me to understand, what kind of specialization this is and how the template parameters ClassType, ReturnType, and Args are deduced?
Many thanks in advance.
What kind of specialization this is?
This is a partial specialization. type_traits is explicitly instantiated with:
T = ReturnType(ClassType::*)(Args...) const
But this T is dependent on ReturnType, ClassType, and Args. That is why you don't have template <> in the declaration (that would be a full specialization), but a template declaration with new parameters describing a particular kind of T.
How the template parameters ClassType, ReturnType, and Args are deduced?
They are deduced when the template is instantiated with an expression that suits this specialization. Here, ReturnType(ClassType::*)(Args...) const can only be substituted with a pointer to a method.
This is an example of SFINAE.
This is a partial specialization. It can't be an "anything" like something that just takes typename T, but it still has some variability in it, so it's not a full specialization.
Also, the things that you're looking to match up are the number of types in the original struct/class's template line and the <...> after the name in the specializations. It's kind of weird because it's asymmetrical.
In your partial specialization:
struct function_traits<ReturnType(ClassType::*)(Args...) const>
All three of the templated types combined still only create a single type - a pointer to member function. That is the same number of types as the "parent" templated type, even though that single type is broken down into 3 additional templated types in the specialization.
// this is what I'm calling the "master template", this isn't an official term
template<class A, class B, ......., class N>
class Foo{};
template</*...This can have as many (or 0) entries as you need for this specialization...*/>
class Foo</*...This must have the same number as master template above, but can be broken down into as many smaller pieces as you want...*/> {};

A type trait for std::array

I am trying to define a type trait that I can use with static_assert to control that one of my template classes is instantiated only with std::array<T,n>. Here is my attempt:
template <typename T>
struct is_std_array : public false_type {};
template <template <typename, size_t> class T, typename V, size_t n>
struct is_std_array<std::array<V, n>> : public true_type {};
But I get the following warning from clang:
warning: class template partial specialization contains a template parameter
that cannot be deduced; this partial specialization will never be used
non-deductible template parameter 'T'
Why is 'T' not deductible? How do I fix that?
Your syntax on specializing is wrong:
template <template <typename, size_t> class T, typename V, size_t n>
You're introducing three template parameters here: the first of which is a template template parameter named T, that takes two parameters: a type and a size_t. Since T is not referenced anywhere in your specialization clause:
struct is_std_array<std::array<V, n>> // <== no T
it's a non-deduced context. Think of the equivalently written function:
template <template <typename, size_t> class T, typename V, size_t n>
void foo(std::array<V, n> );
Here, also, T is a non-deduced context and so would have to be specified explicitly. However, you don't actually need T at all! Just V and n. What you mean is to simply introduce the two relevant parameters directly:
template <typename V, size_t n>
struct is_std_array<std::array<V, n>> : public true_type {};

C++ template partial specialization

I cant figure out how to specialize partially this template. compiler complains that template parameter N is not used in partial specialization
#include <boost/multi_array.hpp>
template<typename T, class A>
struct adaptable;
template<typename T, size_t N>
struct adaptable<T,
// line below is the problem
typename boost::multi_array<T,N>::template array_view<2>::type>
{
typedef typename boost::multi_array<T,N>::template array_view<2>::type type;
};
I can add dummy template parameter just to silence compiler.
template<typename T, class A, class A0 = A>
struct adaptable;
template<typename T, size_t N>
struct adaptable<T,
typename boost::multi_array<T,N>::template array_view<2>::type,
boost::multi_array<T,N> >
{
typedef typename boost::multi_array<T,N>::template array_view<2>::type type;
};
is there more straightforward way?
I don't see anything in your example that looks like partial specialization. A partial specialization is a specialization that specifies exact types for some if the base template parameters, but leaves others open. For example:
template <class T, class U>
struct my_template {
// the base template where both T and U are generic
};
template <class T>
struct my_template<int> {
// A partial specialization where T is still generic, but U == int
};
To support partial specialization, the base template has to have at least two template parameters (call the number N). The partially specialized template can have 1..N-1 template parameters. The partial specialization must be located where the compiler will already have "seen" the base template before attempting to compile the partial specialization. The partial specialization is written as a completely separate template from the base template (though the base template and all specializations must have the same name, of course).