C++ template partial specialization - c++

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).

Related

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 class specialization with template class

Related questions:
c++ nested template specialization with template class
template class specialization with template class parameter
Consider the following code:
template <typename T>
struct is_std_vector: std::false_type { };
template<typename ValueType>
struct is_std_vector<std::vector<ValueType>>: std::true_type { };
Why is such template class specialization syntax correct?
The following seems more logical:
template <typename T>
struct is_std_vector: std::false_type { };
template<> //--- because it is is_std_vector specialization
template<typename ValueType>
struct is_std_vector<std::vector<ValueType>>: std::true_type { };
Class template partial specialization syntax closely mirrors function template syntax. Indeed, the rules for ordering class template partial specializations is based on function template partial ordering.
The way you would write a function taking a vector<T> is:
template <class T>
void is_std_vector(vector<T> ) { ... }
So the way you write a specialization on vector<T> is the same:
template <class T>
class is_std_vector<vector<T>> { ... };
Matching the specialization of is_std_vector would try to deduce T in vector<T> from some type argument A, so it makes a lot of sense that they're written the same way.
For full specializations, we use template <> as placeholder signal to make full specializations look similar to partial specializations. I'm not sure what purpose an extra template <> would serve in this particular case.

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...*/> {};

How to specialize a given template for a template

Is it possible to specialize this template for any basic_string's?
template<class T> struct X {};
Since basic_string is a template itself, I know this would be a solution:
template <template <class, class, class> class T> struct X {}; template <> struct X<basic_string> {};
However, I would like to know if the language allows to preserve the first template definition, by specializing it somehow for basic_string's only.
Yes:
#include <string>
template <typename> struct X;
template <typename TChar, typename TTraits, typename TAlloc>
struct X<std::basic_string<TChar, TTraits, TAlloc>>
{
// ...
};
Your primary template takes one type parameter, so every specialization must supply one type parameter for X, one way or another.

class template partial specialization parametrized on member function return type

The following code, which attempts to specialize class template 'special', based on the return type of member function pointer types, results in a compile error with VC9:
template<class F> struct special {};
template<class C> struct special<void(C::*)()> {};
template<class R, class C> struct special<R(C::*)()> {};
struct s {};
int main()
{
special<void(s::*)()> instance;
return 0;
}
error C2752: 'special' : more than one partial specialization matches the template argument list
The same code is accepted by GCC-4.3.4, as shown by: http://ideone.com/ekWGg
Is this a bug in VC9 and if so, has this bug persisted into VC10?
I have however come up with a horrendously intrusive workaround (for this specific use case, at least. More general solutions welcome):
#include <boost/function_types/result_type.hpp>
#include <boost/type_traits/is_same.hpp>
template<typename F, typename R>
struct is_result_same :
boost::is_same<
typename boost::function_types::result_type<F>::type,
R
>
{};
template<class F, bool = is_result_same<F, void>::value>
struct special {};
template<class R, class C> struct special<R(C::*)(), true> {};
template<class R, class C> struct special<R(C::*)(), false> {};
This is a bug.
template <class C> struct special<void(C::*)()>; // specialization 1
template <class R, class C> struct special<R(C::*)()>; // specialization 2
According to 14.5.4.2, the partial ordering of these two class template specializations are the same as the partial ordering of these imaginary function templates:
template <class C> void f(special<void(C::*)()>); // func-template 3
template <class R, class C> void f(special<R(C::*)()>); // func-template 4
According to 14.5.5.2, the partial ordering of these two function templates is determined by substituting invented types for each type template parameter in the argument list of one and attempting template argument deduction using that argument list in the other function template.
// Rewrite the function templates with different names -
// template argument deduction does not involve overload resolution.
template <class C> void f3(special<void(C::*)()>);
template <class R, class C> void f4(special<R(C::*)()>);
struct ty5 {}; struct ty6 {}; struct ty7 {};
typedef special<void(ty5::*)()> arg3;
typedef special<ty6 (ty7::*)()> arg4;
// compiler internally tests whether these are well-formed and
// the resulting parameter conversion sequences are "exact":
f3(arg4());
f4(arg3());
The details of template argument deduction are in 14.8.2. Among the valid deductions are from template_name<dependent_type> and dependent_type1 (dependent_type2::*)(arg_list). So the f4(arg3()) deduction succeeds, deducing f4<void,ty5>(arg3());. The f3(arg4()) deduction can obviously never succeed, since void and ty6 do not unify.
Therefore function template 3 is more specialized than function template 4. And class template specialization 1 is more specialized than class template specialization 2. So although special<void(s::*)()> matches both specializations, it unambiguously instantiates specialization 1.