partial class template specialization with multiple arguments - c++

I have a template class Foo that takes two (or more) template arguments. I want to use its type in a separate class Bar. See the following simple example, which compiles without error:
template <typename T, typename U> class Foo { };
template <typename T, typename U> class Bar { };
int main()
{
Bar<int, char> bar; // quick example -- int & char could be any 2 types
return 0;
}
The above is somewhat tedious, especially if Foo takes many template arguments and the programmer has to retype them all. I would like to have something like the following instead, but it does not compile:
template <typename T, typename U> class Foo { };
template <typename T, typename U> class Bar; // base
template <typename T, typename U> class Bar< Foo<T, U> > { }; // specialization
int main()
{
typedef Foo<int, char> FooType;
Bar<FooType> bar;
return 0;
}
test.cpp:3:60: error: wrong number of template arguments (1, should be 2)
test.cpp:2:45: error: provided for ‘template class Bar’
test.cpp: In function ‘int main()’:
test.cpp:7:18: error: wrong number of template arguments (1, should be 2)
test.cpp:2:45: error: provided for ‘template class Bar’
test.cpp:7:23: error: invalid type in declaration before ‘;’ token
I am especially perplexed because this partial specialization idiom works fine for a single template argument; see the question titled: total class specialization for a template
Edit I realized that, at least for my purposes, I could get around this using C++11 variadic templates as follows. I still want to know why the second example doesn't work, though.
template <typename... FooTypes> class Bar;
template <typename... FooTypes> class Bar< Foo<FooTypes...> > { };

Your class template Bar<T, U> takes two template arguments, but your specialization is only given one:
template <typename T, typename U> class Bar<Foo<T, U> > {};
Did you mean to have Bar take just one template argument and specialize it correspondingly?
template <typename T> class Bar;
template <typename T, typename U> class Bar<Foo<T, U> > {};
Note that a specialization can depend on a different number of template parameters but the specialization needs to get the same number of arguments. It also works the other way around: a full specialization can have no template parameter:
template <> class Bar<int> {};

I'm a little confused about what you're trying to do in this line:
template <typename T, typename U> class Bar< Foo<T, U> > { }; // specialization
You're stating that the template requires two types, T and U, as type parameters. Foo is itself only one type though, the type created by instantiating the Foo template with those two arguments.
I see that you're expecting it to pick up and determine the T and U since you used them in both places, but that doesn't circumvent the fact that you only provided one type argument for a two type template specialization.

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>> { };

Variadic template argument within template template parameter in a partial specialization

I am trying to develop a generic code that can select different containers types (std::vector, std::map, other), and perform operations over that container wrapper, but I got stuck with the following code:
enum class EContainnerType
{
EContainnerType_Normal,
EContainnerType_OR,
EContainnerType_AND
};
// Base declaration
template<EContainnerType, template<class ... > class ContainerType, class ... ArgType >
struct ConditionContainnerType
{
};
// Partial Specialization
template< template<class ... > class ContainerType, class ... ArgType >
struct ConditionContainnerType<EContainnerType::EContainnerType_OR, ContainerType<ArgType ... >, ArgType ...>
{
};
int main()
{
return 0;
}
The variadic template template argument does not compile, and I get this error:
main.cpp:33:108: error: wrong number of template arguments (2, should be 3)
struct ConditionContainnerType<EContainnerType::EContainnerType_OR,typename ContainerType<ArgType>, ArgType>
^
main.cpp:29:8: error: provided for 'template<EContainnerType <anonymous>, template<class> class ContainerType, class ArgType> struct ConditionContainnerType'
struct ConditionContainnerType
GOAL:
The main goal of this implementation is to perform a certain kind of operation of classification (OR, AND, XOR), this operation is performed on an element that is compared against the generic container.
The operation type is defined by the enum class, and a partial specialization is selected to do the action.
So, if I have a set {a,b,c,d,e} and I fill the set with a specific combination of elements say:
generic_container<Operation_type,generic_set_element> then I want the generic conditional container to perform an action selected by "Operation Type".
So if an element x is compared against the set, the generic container can perform the preselected action over the x element.
Your compiler is broken. The correct error messages look like this (g++ 4.8.2)
error: type/value mismatch at argument 2 in template parameter list for ‘template<EContainnerType <anonymous>, template<class ...> class ContainerType, class ... ArgType> struct ConditionContainnerType’
struct ConditionContainnerType<EContainnerType::EContainnerType_OR,ContainerType<ArgType ... >,ArgType ...>
^
error: expected a class template, got ‘ContainerType<ArgType ...>’
or this (clang 3.3)
error: template argument for template template parameter must be a class template or type alias template
struct ConditionContainnerType<EContainnerType::EContainnerType_OR,ContainerType<ArgType ... >,ArgType ...>
^
They are pretty self-explanatory.
So just remove the parameter.
//Partial Specialization
template< template<class ... > class ContainerType, class ... ArgType >
struct ConditionContainnerType<EContainnerType::EContainnerType_OR,
ContainerType, ArgType ...>
{
};
Now you can write
ConditionContainnerType<EContainnerType::EContainnerType_OR, std::vector, int> a;
ConditionContainnerType<EContainnerType::EContainnerType_OR, std::map, int, int> b;
without having to repeat the parameters twice.
The problem is that you cannot specialize a template-template parameter with a template-template parameter with given template arguments, like forcing:
ContainerType<Args...>
to match:
template <typename...> class BaseContainerType
because it is no longer a template template argument. Instead, a plain ContainerType name would need to be used here, without <Args...> part:
// Base declaration
template <template <typename...> class ContainerType>
struct ConditionContainnerType
{
};
// Partial specialization for two-parameter template template parameter
template <template <typename, typename> class ContainerType>
struct ConditionContainnerType<ContainerType>
{
};
You can, however, specialize the template type itself with a template-template parameter filled with arguments (even with an expanded parameter pack), which goes as follows:
// Base declaration
template <EContainnerType, typename ContainerType, typename... Args>
// ^^^^^^^^^^^^^^^^^^^^^^^ normal type here
struct ConditionContainnerType
{
};
// Partial specialization
template <template <typename...> class ContainerType, typename... Args>
// ^^^^^^^^ template here
struct ConditionContainnerType<EContainnerType::EContainnerType_OR,
ContainerType<Args...>,
// ^^^^^^^ expanded parameter pack
Args...>
{
};
or without a trailing parameter pack:
template <template <typename...> class ContainerType, typename... Args>
struct ConditionContainnerType<EContainnerType::EContainnerType_OR,
ContainerType<Args...>>
{
};
as well as specialize it for templated containers like std::vector<T, A> which take exactly two parameters: type T and allocator A:
template <template <typename, typename> class ContainerType, typename T, typename A>
struct ConditionContainnerType<EContainnerType::EContainnerType_OR,
ContainerType<T, A>,
T>
{
};
Tests:
int main()
{
// base, AND does not match OR
ConditionContainnerType<EContainnerType::EContainnerType_AND
, MyContainer<int>
, int>{};
// specialized, OR and parameter pack matches
ConditionContainnerType<EContainnerType::EContainnerType_OR
, MyContainer<int>
, int>{};
// base, OR matches, but parameters packs do not
ConditionContainnerType<EContainnerType::EContainnerType_OR
, MyContainer<float>
, int>{};
// vector, OR and parameter pack matches
ConditionContainnerType<EContainnerType::EContainnerType_OR
, std::vector<int>
, int>{};
// OR and no parameter-pack
ConditionContainnerType<EContainnerType::EContainnerType_OR
, std::vector<int>>{};
}
DEMO
If otherwise you aim to specialize your base declaration depending on concrete container type (std::vector, std::map), you can do this as follows:
// Base declaration
template <EContainnerType, template <typename...> class ContainerType>
struct ConditionContainnerType
{
};
// Partial specialization for std::vector
template <>
struct ConditionContainnerType<EContainnerType::EContainnerType_OR, std::vector>
// ^^^^^^^^^^^
{
};
// Partial specialization for std::map
template <>
struct ConditionContainnerType<EContainnerType::EContainnerType_AND, std::map>
// ^^^^^^^^
{
};
Tests:
int main()
{
// First specialization
ConditionContainnerType<EContainnerType::EContainnerType_OR, std::vector>{};
// Second specialization
ConditionContainnerType<EContainnerType::EContainnerType_AND, std::map>{};
}
DEMO 2

Partial specialization of type parameter in template class with type & template template parameters

I want to specialize the type parameter of the following template class, which has a type parameter and a template template parameter:
template <
typename T,
template <typename E> class Foo
> class Bar;
I tried every permutation of adding and/or omitting .template and typename in the last line of each of the following snippets, and none compiles:
1.)
template <
template <typename E> class Foo
> class Bar<int, Foo<typename E>>;
2.)
template <
template <typename E> class Foo
> class Bar<int, Foo.template <typename E>>;
3.)
template <
template <typename E> class Foo
> class Bar<int, Foo<E>>;
4.)
template <
template <typename E> class Foo
class Bar<int, Foo.template <E>>;
Why doesn't any of them work?
Regarding the last line of each applicable snippet:
Doesn't typename clarify E is a type used by class Foo, or can this syntax only be used within the {} body of Bar's class definition?
Doesn't template clarify Foo is a template and therefore prevent the compiler from parsing Foo < as Foo "is less than", or can this syntax only be used within the {} body of Bar's class definition?
How can I get this to work?
Doesn't typename clarify E is a type used by class Foo, or can this syntax only be used within the {} body of Bar's class definition?
typename is only used when you are defining a type within a template definition (class could also be used) or when you are accessing a dependent type (a type that depends on a template parameter).
For more information (even about when template is used) see this thread.
How can I get this to work?
The name of a of a type within template template parameter can't actually be used. It's just there as a formality. You have to add another template parameter to your main template instead:
template <
template<typename> class Foo,
typename E
> class Bar<int, Foo<E>> { ... };
Moreover, if this is a specialization of the template Bar, then Bar needs a primary template to specialize:
template<typename T, typename U>
struct Bar;
template <
template<typename> class Foo,
typename E
> class Bar<int, Foo<E>> { ... };
Like this:
template <template <typename E> class Foo>
class Bar<int, Foo>
{
// ...
};
You can even omit the inner parameter name E, since it serves no purpose.

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.

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