The following basic example of partial template class specialization, taken from this wiki page :
template <typename Key, typename Value>
class KeyValuePair { /* something generic */ };
template <typename Key>
class KeyValuePair<Key, bool> { /* something specific to Value=bool */ };
KeyValuePair<int> kvpi;
generates a compiler error :
prog.cpp:10:17: error: wrong number of template arguments (1, should be 2) KeyValuePair<int> kvpi;
Why ? what am I doing wrong ?
How a partial template class specialization should be declared and instantiated ?
I am expecting variable kvpi to be a partially specialized template class instance of type KeyValuePair<int,bool>.
You appear to be confusing partial specialization with default template arguments. It further appears you need both (for reasons unstated, but not really important). Though not entirely intuitive, it can be accomplished as follows:
#include <iostream>
template <typename Key, typename Value = bool>
class KeyValuePair
{
public:
KeyValuePair()
{
std::cout << __PRETTY_FUNCTION__ << ':' << "original\n";
}
};
template <typename Key>
class KeyValuePair<Key, bool>
{
public:
KeyValuePair()
{
std::cout << __PRETTY_FUNCTION__ << ':' << "specialized\n";
}
};
int main()
{
KeyValuePair<int,int> kvp1;
KeyValuePair<int> kvp2;
}
Output
KeyValuePair<int, int>::KeyValuePair() [Key = int, Value = int]:original
KeyValuePair<int, bool>::KeyValuePair() [Key = int, Value = bool]:specialized
The confusing part to some is the default argument specification, but a template that follows which will never actually see fruition with that default-arg because of the later specialization. In such cases I prefer to forward-declare the template with its default argument list. At least for me it makes it slightly easier to read. You may (or not) choose to do the same if you feel it offers clarity. Something like:
template <typename Key, typename Value = bool>
class KeyValuePair;
template <typename Key, typename Value>
class KeyValuePair
{
public:
KeyValuePair()
{
std::cout << __PRETTY_FUNCTION__ << ':' << "original\n";
}
};
template <typename Key>
class KeyValuePair<Key, bool>
{
public:
KeyValuePair()
{
std::cout << __PRETTY_FUNCTION__ << ':' << "specialized\n";
}
};
Partial template specialization doesn't allow you to forget a template parameter. You have to write:
KeyValuePair<int, bool> kvpib;
and correct specialization will be used.
But you can use inheritance to achieve what you want:
template <typename Key>
class KeyBoolPair : public KeyValuePair<Key, bool> {};
KeyBoolPair<int> kbpi;
or if you use C++11 or greater:
template <typename Key>
using KeyBoolPairBis = KeyValuePair<Key, bool>;
KeyBoolPairBis<int> kbpbi;
example: http://coliru.stacked-crooked.com/a/5095fc5c358d291a
You define your partial specialization correctly, but the template expect 2 argument and you provide only one.
You may use default argument:
template <typename Key, typename Value = bool>
class KeyValuePair {};
to allow
KeyValuePair<int> kvpi;
And you may keep your partial specialization if needed
template <typename Key>
class KeyValuePair<Key, bool> { /* something specific to Value=bool */ };
Related
The following basic example of partial template class specialization, taken from this wiki page :
template <typename Key, typename Value>
class KeyValuePair { /* something generic */ };
template <typename Key>
class KeyValuePair<Key, bool> { /* something specific to Value=bool */ };
KeyValuePair<int> kvpi;
generates a compiler error :
prog.cpp:10:17: error: wrong number of template arguments (1, should be 2) KeyValuePair<int> kvpi;
Why ? what am I doing wrong ?
How a partial template class specialization should be declared and instantiated ?
I am expecting variable kvpi to be a partially specialized template class instance of type KeyValuePair<int,bool>.
You appear to be confusing partial specialization with default template arguments. It further appears you need both (for reasons unstated, but not really important). Though not entirely intuitive, it can be accomplished as follows:
#include <iostream>
template <typename Key, typename Value = bool>
class KeyValuePair
{
public:
KeyValuePair()
{
std::cout << __PRETTY_FUNCTION__ << ':' << "original\n";
}
};
template <typename Key>
class KeyValuePair<Key, bool>
{
public:
KeyValuePair()
{
std::cout << __PRETTY_FUNCTION__ << ':' << "specialized\n";
}
};
int main()
{
KeyValuePair<int,int> kvp1;
KeyValuePair<int> kvp2;
}
Output
KeyValuePair<int, int>::KeyValuePair() [Key = int, Value = int]:original
KeyValuePair<int, bool>::KeyValuePair() [Key = int, Value = bool]:specialized
The confusing part to some is the default argument specification, but a template that follows which will never actually see fruition with that default-arg because of the later specialization. In such cases I prefer to forward-declare the template with its default argument list. At least for me it makes it slightly easier to read. You may (or not) choose to do the same if you feel it offers clarity. Something like:
template <typename Key, typename Value = bool>
class KeyValuePair;
template <typename Key, typename Value>
class KeyValuePair
{
public:
KeyValuePair()
{
std::cout << __PRETTY_FUNCTION__ << ':' << "original\n";
}
};
template <typename Key>
class KeyValuePair<Key, bool>
{
public:
KeyValuePair()
{
std::cout << __PRETTY_FUNCTION__ << ':' << "specialized\n";
}
};
Partial template specialization doesn't allow you to forget a template parameter. You have to write:
KeyValuePair<int, bool> kvpib;
and correct specialization will be used.
But you can use inheritance to achieve what you want:
template <typename Key>
class KeyBoolPair : public KeyValuePair<Key, bool> {};
KeyBoolPair<int> kbpi;
or if you use C++11 or greater:
template <typename Key>
using KeyBoolPairBis = KeyValuePair<Key, bool>;
KeyBoolPairBis<int> kbpbi;
example: http://coliru.stacked-crooked.com/a/5095fc5c358d291a
You define your partial specialization correctly, but the template expect 2 argument and you provide only one.
You may use default argument:
template <typename Key, typename Value = bool>
class KeyValuePair {};
to allow
KeyValuePair<int> kvpi;
And you may keep your partial specialization if needed
template <typename Key>
class KeyValuePair<Key, bool> { /* something specific to Value=bool */ };
I have some templated class types like A,B,C as follows:
template < typename T >
class A{};
template < typename T >
class B{};
template < typename T >
class C{};
And now I want to have a function which accepts in general any type like:
template < typename T>
void Func()
{
std::cout << "Default " << __PRETTY_FUNCTION__ << std::endl;
}
And now I want to specialize the function to only accept one of the given template classes like:
template < typename T>
void Func<A<T>>()
{
std::cout << "All A Types " << __PRETTY_FUNCTION__ << std::endl;
}
Which is not allowed because it is only a partial specialization. OK.
I think concept may help but it feels that I think much too complicated. My solution is:
template < typename T, template <typename > typename OUTER >
bool Check;
template < typename INNER, template < typename > typename OUTER, template < typename> typename T>
constexpr bool Check< T<INNER>, OUTER > = std::is_same_v< OUTER<INNER>, T<INNER>>;
template < typename T >
concept IsA = Check< T, A >;
template < typename T >
concept IsB = Check< T, B >;
template < IsA T >
void Func()
{
std::cout << "All A Types " << __PRETTY_FUNCTION__ << std::endl;
}
template < IsB T >
void Func()
{
std::cout << "All B Types " << __PRETTY_FUNCTION__ << std::endl;
}
int main()
{
Func<A<int>>();
Func<B<int>>();
Func<C<int>>();
}
It feels a bit complicated to me. Can that be simplified? Would be nice if the Check template can be removed. Any idea?
See full example here live
One common workaround would go like this:
template <typename T>
struct FuncImpl {
static void Run() { std::cout << "Default"; }
};
template <typename T>
struct FuncImpl<A<T>> {
static void Run() { std::cout << "Specialized for A<T>"; }
};
template <typename T>
void Func() { FuncImpl<T>::Run(); }
Function templates cannot be partially specialized, but class templates can be; so we just delegate from the former to the latter.
It feels a bit complicated to me. Can that be simplified? Would be nice if the Check template can be removed. Any idea?
Much of complexity and in-elegance is in the fact you need a new concept for every class template. Write a general-purpose and reusable concept, and it is no longer complicated to use.
template <typename T, template <typename...> class TT>
constexpr bool is_instantiation_of_v = false;
template <template <typename...> class TT, typename... TS>
constexpr bool is_instantiation_of_v <TT<TS...>, TT> = true;
template <class C, template<typename...> class TT>
concept instantiation_of = is_instantiation_of_v<C, TT>;
The same principle as yours, except the checker is usable with a template taking any number of type arguments. Meanwhile, the concept accepts the same parameters. The first parameter has a special meaning and is implicitly understood to be the constrained template parameter in the short-hand syntax. The rest (the template template-parameter) must be given explicitly.
How can it be used? Like this
template <instantiation_of<A> T>
int Func()
{
return 'A';
}
template <instantiation_of<B> T>
int Func()
{
return 'B';
}
Got a new class template to constrain over? No problem, this concept works without additional boiler-plate.
template <instantiation_of<D> T>
int Func()
{
return 'D';
}
OP writes:
Yes, would be nice to write some "instant" code directly in the functions template parameter... if possible...
Normally, to determine whether it's a specialization of some given class template, we define a trait ahead of time and then check whether the type satisfies that trait. If you don't want to define anything ahead of time, you have to find a way to perform template argument deduction inline, so you can check whether it succeeds. In C++20, this is straightforward but a bit ugly:
template <typename T>
void Func()
{
std::cout << "unconstrained" << std::endl;
}
template <typename T>
requires requires {
[]<typename U>(const A<U>&){}(std::declval<T>());
}
void Func()
{
std::cout << "constrained" << std::endl;
}
Here, the requires-clause checks whether T can be bound to an argument of type const A<U>& for some deducible U. You can see this example here: https://godbolt.org/z/dTEbaaPvh
This isn't exactly pleasant to read. If you will be using this hack multiple times, I think it's better to just define traits instead. I've answered your question simply to satisfy your curiosity, not to recommend this technique.
The version above will pick the constrained version not only when the template argument is some A<U> but also when it is possibly cv-qualified, possibly ref-qualified, and possibly publicly derived from A<U>. Some tweaks are possible to make the constraint more strict.
#include <iostream>
using namespace std;
template <typename T = int>
struct Foo {
T t;
Foo() { cout << "Foo" << endl; }
};
template <typename T>
struct Baz {
T t;
Baz() { cout << "Baz" << endl; }
};
template <typename T>
struct Bar {
T t;
Bar() { cout << "Bar" << endl; }
};
template <template <typename X> class T>
struct Bar {
T data;
Bar() : data() { cout << "Bar" << endl; }
};
int main()
{
Bar<Foo<>> a;
Bar<Baz<float>> b;
Bar<int> c;
return 0;
}
I'm just beginning to learn about templates. And I am really confused with template template parameters. I understand that you are passing a template as an argument. In my template class for Bar where it receives a template template argument, what does <typename X> represent? Is typename X a template parameter for class T?
template <template <typename X> class T>
struct Bar {
T data;
Bar() : data() { cout << "Bar" << endl; }
};
Also, when I call my template template argument in the main function, I get errors that there are no default constructors for Bar. Why is that?
template template parameters allow you pass templates to other templates.
They are not concrete types and need to be parameterised order to instaciate them.
In my template class for Bar where it receives a template template
argument, what does <typename X> represent?
From the standard [basic.scope.temp];
The declarative region of the name of a template parameter of a
template template-parameter is the smallest template-parameter-list in
which the name was introduced.
This basically says the name is only available within the that template template's parameters list.
For many cases it is sufficient to just put typename without a name for a template template parameter, but names may serve to document your code.
However an example of when it is useful to give it a name is if another non type template parameter depends on it.
For example, template <template <typename X, X> typename Y>.
With respect too your sample code, you have two problems with the second declaration of Bar. First is that Bar has already been declared to accept a type, not a template.
Your second declaration conflicts as it is declared to accept a template.
What you require here is a specialization of Bar, where the specialization resolves to a single Type, matching the primary template.
For instance,
template <template <typename> class T,typename Y>
struct Bar<T<Y>> {
T<Y> data;
Bar() : data() { cout << "Bar" << endl; }
};
The important thing to notice here is that the template parameters in the specialization can be whatever you need. It is the part after struct Bar that must match the primary template. All of the parameters in the specialization will be deduced from the type passed as the template parameter to your instantiation of Bar.
Your second problem is that you declare a member of Bar to be of type T. T is a template in the second case, and you cannot instantiate a template
without parameterising it.
Here is a working example of your code with the specialization of Bar.
#include <iostream>
using namespace std;
template <typename T = int>
struct Foo {
T t;
Foo() { cout << "Foo" << endl; }
};
template <typename T>
struct Baz {
T t;
Baz() { cout << "Baz" << endl; }
};
template <typename T>
struct Bar {
T t;
Bar() { cout << "Bar" << endl; }
};
template <template <typename > class T,class Y>
struct Bar<T<Y>>
{
T<Y> data;
Bar() : data() { cout << "Bar Specialization" << endl; }
};
int main()
{
Bar<Foo<>> a; //matches the specialization with T = template<typename> Foo and Y=int
Bar<Baz<float>> b; //matches the specialization with T = template<typename> Baz and Y=float
Bar<int> c; //matches the primary template with T=int
return 0;
}
Demo
typename X is only part of the template template parameters signature, you can just aswell write template<template<typename> class T> (without a name for the parameter of T).
Since T is itself a template, you need to instantiate it before you can use it as a class. The signature tells you what the template needs to be instantiated, in this case, it needs one type name.
template<typename X>
struct GenericThing
{
X data;
};
template<template<typename> class T, typename E>
struct Bar
{
T<E> sub; // instantiate T with E
Bar() : sub() { cout << "Bar" << endl; }
};
int main()
{
Bar<GenericThing, int> intbar;
Bar<GenericThing, float> floatbar;
return 0;
}
template <typename T>
void func_template(T& con) {
for (const auto& c : con)
std::cout << c << std::endl;
}
/*
Nested Templates
template <
template <
// # of type args that will be included in the nested template
typename,
...
>
// # of different types yo
typename T1,
...
typename TN
>
*/
template <template<typename, typename> typename V, typename T>
void func_template3(V<T, std::allocator<T>>& vec) {
for (const auto& elem : vec)
std::cout << elem << std::endl;
}
template <template<typename, typename, typename, typename> typename M, typename T1, typename T2>
void func_template4(M<T1, T2, std::less<T1>, std::allocator<std::pair<const T1, T2>>> & dict) {
for (const auto& pair : dict)
std::cout << pair.first << " " << pair.second << std::endl;
}
I just learned C++ a month ago, so please bear with me. The above is the way I personally look at it. the func_template3 and func_template4 provides an example of a template printing vector and map containing any type. I find that paying attention to VS "No instance of function template 'XXXX' matches the argument list error" very useful in trying to determine the composition of built-in types for the data structure that you should include in the template.
For example:
Prior to implementing to func_template4, I used an std::map variable as an argument for func_template3, which then VS prompted me with the following error
So when I was implementing funct_template4, I basically used the "arguments types are:(..." part of the error to guide me on what other built-in types should be included.
I've heard arguments that implementing nested templates are typically unnecessary, since it could have been achieved via func_template1; however, I somewhat disagree because the code that you would write in func_template1 actually depend largely on what data structure you intend to use the template with. Just my 2 cents from a C++ noob.
Is there a way to use a variadic template as a Key template parameter in std::unordered_map?
I tried to do it in this way:
template<typename T, typename ...Args>
class Wrapper {
public:
// some staff
private:
unordered_map<Args, T> hashmap;
};
But got this error:
Error C3520 'Args': parameter pack must be expanded in this context
Is there a way to use a variadic template as a Key template parameter in std::unordered_map?
No, as far I know: std::unordered_map require a single key type and a single value type.
But if your intention is to have a hashmap, in the Wrapper class, for every type in Args..., and if the Args... types are all different, you can obtain it through another inheritance and another level of wrapping
template <typename K, typename V>
struct wrpH
{ std::unordered_map<K, V> hashmap; };
template <typename T, typename ...Args>
class Wrapper : public wrpH<Args, T>...
{ };
The problem of this solution is that you have more hashmap in the same class and to access they you have to explicit the corresponding base struct; something as follows
w.wrpH<Args, T>::hashmap[argsValue] = tValue;
The following is a full working example
#include <iostream>
#include <unordered_map>
template <typename K, typename V>
struct wrpH
{ std::unordered_map<K, V> hashmap; };
template <typename T, typename ...Args>
class Wrapper : public wrpH<Args, T>...
{ };
int main()
{
Wrapper<int, int, long, long long> w;
w.wrpH<long, int>::hashmap[1L] = 2;
std::cout << w.wrpH<int, int>::hashmap.size() << std::endl;
std::cout << w.wrpH<long, int>::hashmap.size() << std::endl;
std::cout << w.wrpH<long long, int>::hashmap.size() << std::endl;
}
If, on the contrary, you need a single hashmap with a key that is a combination of all Args... types, you can use, as key type, a class that receive a variadic list of types as template paramenters. As suggested in comments, std::tuple is the obvious choice
std::unordered_map<std::tuple<Args...>, T> hashmap;
This works also if some types in Args... coincide.
Possibly easy to solve, but its hard to find a solution to this:
Is it possible to (partially) specialize for a whole set of types?
In the example "Foo" should be partially specialized for (T,int) and (T,double) with only one template definition.
What I can do is define a specialisation for (T,int). See below. But, it should be for (T,int) and (T,double) with only one function definition (no code doubling).
template <typename T,typename T2>
struct Foo
{
static inline void apply(T a, T2 b)
{
cout << "we are in the generic template definition" << endl;
}
};
// partial (T,*)
template <typename T>
struct Foo<T, int > // here something needed like T2=(int, double)
{
static inline void apply(T a, T2 b)
{
cout << "we are in the partial specialisation for (T,int)" << endl;
}
};
Any ideas how to partially specialize this for (T,int) and (T,double) with one template definition?
If I understood your question correctly, then you can write a base class template and derive from it, as illustrated below:
template <typename T, typename U>
struct Foo_Base
{
static inline void apply(T a)
{
cout << "we are in the partial specialisation Foo_Base(T)" << endl;
}
};
template <typename T>
struct Foo<T, int> : Foo_Base<T, int> {};
template <typename T>
struct Foo<T, double> : Foo_Base<T, double> {};
Although its not one template definition (as you asked for), but you can avoid the code duplication.
Demo : http://www.ideone.com/s4anA
I believe you could do this using Boost's enable_if to enable the partial specialisation for just the types you want. Section 3.1 shows how, and gives this example:
template <class T, class Enable = void>
class A { ... };
template <class T>
class A<T, typename enable_if<is_integral<T> >::type> { ... };