If you have a class template such as this:
template <typename T, unsigned CAPACITY>
class Collection
{
T m_array[CAPACITY]{};
T m_dummy{};
unsigned m_size{};
}
public:
void display(std::ostream& ostr = std::cout) const
{
ostr << "----------------------" << std::endl;
ostr << "| Collection Content |" << std::endl;
ostr << "----------------------" << std::endl;
}
And I wanted to create specialization depending on the type used, but not the CAPACITY, is this possible?
I have this, which works:
void Collection<Pair, 50u>::display(std::ostream& ostr) const
{
ostr << "----------------------" << std::endl;
ostr << "| This is a Pair |" << std::endl;
ostr << "----------------------" << std::endl;
}
When it is called as:
Collection<Pair, 50> colDictionary;
But this only works if the type is Pair, as well as the exact CAPACITY is 50.
This is what I had in mind, allowing for type to be Pair and CAPACITY to be anything:
void Collection<Pair>::display(std::ostream& ostr) const
{
ostr << "----------------------" << std::endl;
ostr << "| This is a Pair |" << std::endl;
ostr << "----------------------" << std::endl;
}
But this causes a "too few arguments for class template" error.
Any way to do this without changing the actual class template itself?
It's called a partial template specialization:
template <class T, unsigned Capacity>
struct Collection {
};
template <unsigned Capacity>
struct Collection<Pair, Capacity> {
// Specialize
};
One thing to note is that you cannot partially specialize a single function. You have to specialize the whole class template, which is irritating if the class template is long. Another quick-and-dirty way of doing this if you want to specialize a single function would be to just use a "compile-time if":
#include <type_traits>
template <class T, unsigned Capacity>
struct Collection {
void display() const {
if constexpr (std::is_same_v<T, Pair>) {
// pair implementation
} else {
// general implementation
}
}
};
Or, as a more clean solution, try moving the whole thing out of the class and add a simple overload:
// Free-standing overloads:
template <class T, unsigned Capacity>
void diplay(Collection<T, Capacity> const& c) { /* ... */ }
template <unsigned Capacity>
void display(Collection<Pair, Capacity> const& c) { /* ... */ }
// The member function delegates the work to
// the overloaded functions. No template specialization
// is involved:
template <class T, unsigned Capacity>
struct Capacity {
void display() const {
display(*this); // calls the correct overload.
}
};
It seems difficult to do a partial specification.
Some ways are helpful for you to achieve it:
Define a specification class for this type situation.
If you just only desire to custom this behavior(but not too much and it's limited), you can use if-constexpr branches.
If you want to avoid a class-partial-template (because it's a burden to rewrite all codes), then use a global function template is helpful.
Some suggested codes are given:
#include <iostream>
template <typename T, unsigned capacity>
class Collection {
public:
void display(std::ostream &ostr = std::cout) const;
};
template <typename T, unsigned c>
void Collection<T, c>::display(std::ostream &ostr) const {
if constexpr (c == 50u) {
ostr << "Specification! \n";
} else {
ostr << "Normal Realization. \n";
}
}
int main() {
Collection<int, 50> c;
c.display();
}
If you need to specialize a certain member function, you can use the Curiously Recurring Template Pattern (or CRTP for short). You'd then create a base class and a specialization of that base class. Both contain only the specific member function that you want to specialize.
template <class T, class CRTP, unsigned Capacity>
struct display_impl {
void display() const {
auto& This = static_cast<const CRTP&>(*this);
// Use `This` to access members of Collection
}
};
template <class CRTP, unsigned Capacity>
struct display_impl<Pair, CRTP, Capacity> {
void display() const {
auto& This = static_cast<const CRTP&>(*this);
// Use `This` to access members of Collection
}
};
Collection will now inherit from display_impl and supply itself as a template parameter:
template <class T, unsigned Capacity>
struct Collection : display_impl<T, Collection<T, Capacity>, Capacity> {
friend struct display_impl<T, Collection<T, Capacity>, Capacity>;
};
Demo
Related
I'm trying to write a very simple specialized class template that has a member variable and can print that member variable differently in specialized situations. I know the example is pretty useless, but it illustrates the question pretty well.
When specializing class templates it seems that the specializations of the class don't share the same member variables, so the following code won't compile...
#include <iostream>
#include <string>
// Class template
template <typename T>
struct S
{
S(const T& t)
: t(t)
{}
void print()
{
std::cout << t << std::endl;
}
private:
T t;
};
// Specialization
template <>
struct S<std::string>
{
void print()
{
// ERROR: "t" is not defined in this context
std::cout << "string: " << t << std::endl;
}
};
This suggests that I would need to write a separate constructor for every specialization and have a separate member variable t for each specialization which feels like it would quickly become a lot of duplicated code and effort if I have many specializations.
If what I am saying is true, then is it bad practice to use member variables in specialized class templates altogether? Are there any alternatives that result in less code duplication?
Please also look at #0x499602D2's answer, it is simpler and works for many practical cases.
You are correct, the specializations are basically totally independet from each other and the original template, so you would have to write everything new. A way to get around that would be to use inheritance.
#include <iostream>
#include <string>
// Class template
template <typename T>
struct Base
{
Base(const T& t)
: t(t)
{}
virtual void print()
{
std::cout << t << std::endl;
}
protected:
T t;
};
template<class T>
struct S: Base<T> {
};
// Specialization
template <>
struct S<std::string>: Base<std::string>
{
void print() override
{
std::cout << "string: " << t << std::endl;
}
};
Since you are only specializing a single template parameter, you can explicitly specialize the member function instead of the entire class:
template <>
void S<std::string>::print()
{
std::cout << "string: " << t << std::endl;
}
Another possible solution is tag-dispatcing
template <typename T>
struct S
{
private:
T t;
void print_helper (std::true_type) // T is std::string
{ std::cout << "string: " << t << std::endl; }
void print_helper (std::false_type) // T isn't std::string
{ std::cout << t << std::endl; }
public:
S (T const & t0) : t{t0}
{ }
void print ()
{ print_helper(std::is_same<T, std::string>{}); }
};
Another way to do it is to use a helper function. This will let you do partial template specialization kind of, working around the issue noted by #0x499602D2. What we're doing is having the templated function call a helper function and the helper function is doing all the specialization.
I added another template parameter into there to show that this solution kind of works for partial template specialization. Notice that the templated helper function is full-specialized, not partially. You can't partially specialize a function. This can be useful in cases when the class template has more template parameters that you can't specialize (UNUSED_T) but the function that you do want to specialize can be fully specialized (print_it doesn't need the UNUSED_T).
#include <iostream>
#include <string>
// This is the helper function for all types T...
template <typename T>
void print_it(T t) {
std::cout << t << std::endl;
}
// ... except for std::string, it will run this one.
template <>
void print_it<std::string>(std::string t) {
std::cout << "string: " << t << std::endl;
}
// Class template, UNUSED is there just to show that
// this works for partial template specialization.
template <typename T, typename UNUSED_T>
struct S {
S(const T& t) : t(t) {}
void print() {
// You can remove the <T> because
// the compiler will figure it out for you.
print_it<T>(t);
}
prviate:
T t;
UNUSED_T unused;
};
int main() {
S<uint, char> x(5);
x.print(); // OUTPUT: 5
S<std::string, char> y("foo");
y.print(); // OUTPUT: string: foo
}
I want to specialise a single template method in a non-template class to use an std::vector however only the return type of the method uses the template.
#include <iostream>
#include <string>
#include <vector>
class Foo
{
public:
template<typename T>
T Get()
{
std::cout << "generic" << std::endl;
return T();
}
};
template<>
int Foo::Get()
{
std::cout << "int" << std::endl;
return 12;
}
template<typename T>
std::vector<T> Foo::Get()
{
std::cout << "vector" << std::endl;
return std::vector<T>();
}
int main()
{
Foo foo;
auto s = foo.Get<std::string>();
auto i = foo.Get<int>();
}
This compiles with an error indicating that the std::vector attempted specialisation does not match any prototype of Foo, which is completely understandable.
In case it matters, use of C++14 is fine and dandy.
You can only partially specialize classes (structs) (cppreference) - so the way to overcome your problems is to add helper struct to allow this partial specialization of std::vector<T> - e.g. this way:
class Foo
{
private: // might be also protected or public, depending on your design
template<typename T>
struct GetImpl
{
T operator()()
{
std::cout << "generic" << std::endl;
return T();
}
};
public:
template<typename T>
auto Get()
{
return GetImpl<T>{}();
}
};
For int - you can fully specialize this function:
template<>
int Foo::GetImpl<int>::operator()()
{
std::cout << "int" << std::endl;
return 12;
}
For std::vector<T> you have to specialize entire struct:
template<typename T>
struct Foo::GetImpl<std::vector<T>>
{
std::vector<T> operator()()
{
std::cout << "vector" << std::endl;
return std::vector<T>();
}
};
Partial specialisation of template functions (including member functions) is not allowed. One option is to overload instead using SFINAE. For example,
/// auxiliary for is_std_vetor<> below
struct convertible_from_std::vector
{
template<typename T>
convertible_from_std::vector(std::vector<T> const&);
};
template<typename V>
using is_std_vector
= std::is_convertible<V,convertible_from_std_vector>;
class Foo
{
public:
template<typename T, std::enable_if_t< is_std::vector<T>::value,T>
Get()
{
std::cout << "vector" << std::endl;
return T();
}
template<typename T, std::enable_if_t<!is_std::vector<T>::value,T>
Get()
{
std::cout << "generic" << std::endl;
return T();
}
};
Note that the helper class is_std_vector may be useful in other contexts as well, so it worth having somewhere. Note further that you can make this helper class more versatile by asking for any std::vector or specific std::vector<specific_type, specific_allocator>. For example,
namespace traits {
struct Anytype {};
namespace details {
/// a class that is convertible form C<T,T>
/// if either T==AnyType, any type is possible
template<template<typename,typename> C, typename T1=Anytype,
typename T2=Anytype>
struct convCtTT
{
convCtTT(C<T1,T2> const&);
};
template<template<typename,typename> C, typename T1=Anytype>
struct convCtTT<C,T1,AnyType>
{
template<typename T2>
convCtTT(C<T1,T2> const&);
};
template<template<typename,typename> C, typename T2=Anytype>
struct convCtTT<C,AnyType,T2>
{
template<typename T1>
convCtTT(C<T1,T2> const&);
};
template<template<typename,typename> C>
struct convCtTT<C,AnyType,AnyType>
{
template<typename T1, typename T2>
convCtTT(C<T1,T2> const&);
};
}
template<typename Vector, typename ValueType=AnyType,
typename Allocator=AnyType>
using is_std_vector
= std::is_convertible<Vector,details::convCtTT<std::vector,ValueType,
Allocator>;
}
You can't partially specialze template in c++. You need to overload your function and pass the type in parameters.
#include <iostream>
#include <string>
#include <vector>
class Foo
{
public:
template<typename T>
T Get()
{
return this->getTemplate(static_cast<T*>(0)); //
}
private:
template<class T> T getTemplate(T* t)
{
std::cout << "generic" << std::endl;
return T();
}
template<class T> std::vector<T> getTemplate(std::vector<T>* t)
{
std::cout << "vector" << std::endl;
return std::vector<T>();
}
};
template <> int Foo::getTemplate(int* t)
{
std::cout << "int" << std::endl;
return 12;
}
int main()
{
Foo foo;
auto s = foo.Get<std::string>();
auto i = foo.Get<int>();
auto v = foo.Get<std::vector<int>>();
}
Edit : fixed a typo in the code
I've got following class:
class Foo {
public:
template <typename T>
T bar() {
cout << "Called with return type: " << typeid(T).name() << endl;
T t = //... (some implementation here)
return t;
}
}
It's invoked in following way:
Foo foo;
int i = foo.bar<int>();
long l = foo.bar<long>();
Now i'd like to have different specialization for cases when function is invoked with shared_ptr<T>
Foo foo;
foo.bar<shared_ptr<int>>();
foo.bar<shared_ptr<long>>();
But of course I don't want to create full specialization for each type. Is it possible to implement such behaviour (can be trait-based if required)?
You cannot partially specialize functions. For a story on why, check out this GOTW.
You can partially specialize classes though, so what you could do is:
template <typename T>
T bar() {
return bar_impl<T>::apply(this);
}
Where:
template <typename T>
struct bar_impl {
static T apply(Foo* ) {
// whatever
}
}
template <typename T>
struct bar_impl<std::shared_ptr<T>> {
static std::shared_ptr<T> apply(Foo* ) {
// whatever else
}
}
There's certainly many ways to do it. The first way that comes to my mind is simply function overloading. Since you don't have a parameter to overload on, you'll have to make one. I like pointers, which effectively act as a way to pass types to functions.
class Foo {
//regular overload
template<typename T>
T bar(T*) { //takes a pointer with an NULL value
cout << "Called with return type: " << typeid(T).name() << endl;
T t = //... (some implementation here)
return t;
}
//shared_ptr overload - NOTE THAT T IS THE POINTEE, NOT THE SHARED_PTR
template<typename T>
std::shared_ptr<T> bar(std::shared_ptr<T>*) { //takes a pointer with an null value
cout << "Called with return type: " << typeid(T).name() << endl;
std::shared_ptr<T> t = //... (some implementation here)
return t;
}
public:
template <typename T>
T bar() {
T* overloadable_pointer = 0;
return bar(overloadable_pointer);
}
};
I've never heard of anyone else using pointers to pass types around, so if you choose to do this, comment thoroughly, just to be safe. It is wierd code.
It may be more intuitive to simply use a helper struct to do template specialization, which is what most people would do. Unfortunately, if you need access to the members of Foo (which you presumably do), using template specialization would require you to pass all those members to the function, or friend the template helpers. Alternatively, you could pass a type_traits specialization thing to another member, but that ends up simply being a complex version of the pointer trick above. Many find it more normal and less confusing though, so here's that:
template<typename T>
struct Foo_tag {};
class Foo {
//regular overload
template<typename T>
T bar(Foo_tag<T>) {
}
//shared_ptr overload - NOTE THAT T IS THE POINTEE, NOT THE SHARED_PTR
template<typename T>
std::shared_ptr<T> bar(Foo_tag<std::shared_ptr<T>>) {
}
public:
template <typename T>
T bar() {
return bar(Foo_tag<T>{});
}
}
Since noone proposed it yet, one can use SFINAE to distinguish between T and std::shared_ptr<U>:
template <typename T>
struct is_shared_ptr_impl : std::false_type {};
template <typename T>
struct is_shared_ptr_impl<std::shared_ptr<T>> : std::true_type {};
template <typename T>
using is_shared_ptr = typename is_shared_ptr_impl<typename std::decay<T>::type>::type;
class Foo
{
public:
template <typename T>
auto bar()
-> typename std::enable_if<!is_shared_ptr<T>{}, T>::type
{
std::cout << "T is " << typeid(T).name() << std::endl;
return {};
}
template <typename T>
auto bar()
-> typename std::enable_if<is_shared_ptr<T>{}, T>::type
{
using U = typename std::decay<T>::type::element_type;
std::cout << "T is shared_ptr of " << typeid(U).name() << std::endl;
return {};
}
};
DEMO
When playing around with good ol' c++ I started wondering whether it is possible to overload a template function based on an enclosing template. At the first layer this looks achievable, however, how can this be done recursively? So that the below pseudo-c++ code
#include <iostream>
#include <vector>
#include <map>
template <typename T> void magic(){
std::cout << "Called magic<T>" << std::endl;
}
template <typename std::vector<T> > void magic(){
std::cout << "Called magic<std::vector<T> >" << std::endl;
magic<T>();
}
template <typename std::map<T,U> > void magic(){
std::cout << "Called magic<std::map<T,U> >" << std::endl;
magic<T>();
magic<U>();
}
int main() {
magic<std::vector<std::map<std::string,std::vector<int> > > >();
}
yields something like:
Called magic<std::vector<T> >
Called magic<std::map<T,U> >
Called magic<T>
Called magic<std::vector<T> >
Called magic<T>
In principle this does not look like it should be impossible because all the type info is available at compile time. The compiler could easily create all required functions since the recursion is bound to stop. And thus the question: Is this possible? If so, how?
Simple specialization should do the trick, but bear in mind that you cannot specialize function templates partially, so you'll need an intermediate class template:
template <typename> void magic();
template <typename T>
struct Impl
{
static void f() { std::cout << "Primary template\n"; }
};
template <typename T, typename A>
struct Impl<std::vector<T, A>>
{
static void f() { std::cout << "A vector\n"; magic<T>(); }
};
template <typename K, typename T, typename P, typename A>
struct Impl<std::map<K, T, P, A>>
{
static void f() { std::cout << "A map\n"; magic<K>(); magic<T>(); }
};
template <typename T> void magic() { Impl<T>::f(); }
You need partial template specialization, that is a template specialization which itself is a template again.
That is not possible with function templates but it is with classes. So the workaround is to create a class template (here called Magic) with the specializations. Within that class, a simple (non-template) function is called.
Then, a function magic forwards to that class in order to hide that "hack":
Live demo of this code snippet
#include <iostream>
#include <vector>
#include <map>
// Forward declaration of the magic function:
template <typename> void magic();
// General case:
template <typename T>
struct Magic {
static void m(){
std::cout << "Called magic<T>" << std::endl;
}
};
// Vector case:
template <typename T>
struct Magic<std::vector<T> > {
static void m(){
std::cout << "Called magic<std::vector<T> >" << std::endl;
magic<T>();
}
};
// Map case:
template <typename T, typename U>
struct Magic<std::map<T,U> > {
static void m(){
std::cout << "Called magic<std::map<T> >" << std::endl;
magic<T>();
magic<U>();
}
};
// Implementation of the magic function:
template <typename T>
void magic() {
std::cout << "Forwarding..." << std::endl;
Magic<T>::m();
}
int main() {
magic<std::vector<std::map<std::string,std::vector<int> > > >();
}
consider the code
template <class A>
class B;
template <class A>
class B<const A>{};
template <class A, int N>
class B<A[N]>{};
template <class A>
class B<A*>{};
template <class A>
class B<A&>{};
The following template instantiations work fine:
A<int*&>
A<const int*>
A<int*[3]>
but the following one doesn't work:
A<const int[3]>
Is there some reason that this particular combination is invalid or is it perhaps a bug with g++4.6.3?
By the way I managed to get around this using SFINAE and boost::disable_if<>, so at least the problem is solved.
EDIT
I forgot to mention that the error in question is an ambiguous class template instantiation and it couldn't decide between the overload for const or the overload for an array.
EDIT2
This has nothing to do with pointers, here's the full context:
I'm going through the book C++ Template Metaprogramming and am doing question 2-3 (Chapter 2 question 3) which says:
Use the type traits facilities to implement a type_descriptor class template, whose instances, when streamed, print the type of their template parameters:
NOTE: we cannot use RTTI to the same effect since, according to 18.5.1 [lib.type.info] paragraph 7 of the standard, typeid(T).name() is not guaranteed to return a meaningful result.
My solution (including the the workaround for the compilation error) is as follows:
//QUESTION 2-3
template <class T, class enable = void>
struct type_descriptor
{
std::string operator()() const
{
return "Unknown";
}
};
//specializations for primitive types
#define TYPE_DESC_SPEC(type) template <> \
struct type_descriptor<type,void> \
{std::string operator()() const{return #type;}};
TYPE_DESC_SPEC(int)
TYPE_DESC_SPEC(long)
TYPE_DESC_SPEC(void)
TYPE_DESC_SPEC(short)
TYPE_DESC_SPEC(unsigned char)
TYPE_DESC_SPEC(unsigned short)
TYPE_DESC_SPEC(unsigned long)
//specializations for modifiers *, const, &, and [N]
template <class T>
struct type_descriptor<T&,void>
{std::string operator()(){return type_descriptor<T>()() + " &";}};
template <class T>
struct type_descriptor<T*,void>
{std::string operator()(){return type_descriptor<T>()() + " *";}};
//Replace void with what's in the comment for the workaround.
template <class T>
struct type_descriptor<const T, void/*typename boost::disable_if<boost::is_array<T> >::type*/>
{std::string operator()(){return type_descriptor<T>()() + " const";}};
template <class T>
struct type_descriptor<T(*)(),void>
{std::string operator()(){return type_descriptor<T>()() + " (*)()";}};
template <class T, class U>
struct type_descriptor<T(*)(U),void>
{std::string operator()(){return type_descriptor<T>()() + " (*)(" + type_descriptor<U>()() + ")";}};
template <class T, int N>
struct type_descriptor<T[N],void>
{
std::string operator()()
{
std::stringstream s;
s << type_descriptor<T>()() << " [" << N << "]";
return s.str();
}
};
template <class T>
struct type_descriptor<T[],void>
{std::string operator()(){return type_descriptor<T>()() + " []";}};
//Now overload operator<< to allow streaming of this class directly
template <class T>
std::ostream & operator<<(std::ostream & s, type_descriptor<T> t)
{
return s << t();
}
//END QUESTION 2-3
Sample usage is:
std::cout << "\nQuestion 2-3 results\n";
std::cout << type_descriptor<int*>() << std::endl;
std::cout << type_descriptor<int*[3]>() << std::endl;
std::cout << type_descriptor<std::string*>() << std::endl;
std::cout << type_descriptor<const int&>() << std::endl;
std::cout << type_descriptor<const int *const&>() << std::endl;
std::cout << type_descriptor<int[4]>() << std::endl;
std::cout << type_descriptor<int(*)()>() << std::endl;
std::cout << type_descriptor<int*&(*)(const char &)>() << std::endl;
std::cout << type_descriptor<int*&>() << std::endl;
std::cout << type_descriptor<int[]>() << std::endl;
std::cout << type_descriptor<const long[]>() << std::endl;
and the corresponding output is (when the workaround is in, otherwise it doesn't compile on that last one):
int *
int * [3]
Unknown *
int const &
int const * const &
int [4]
int (*)()
int * & (*)(Unknown const &)
int * &
int []
long const []
So C++ is able to differentiate pointers and arrays for the template parameters, is able to correctly, recursively, separate compound types and output the correct result, except for const A[]. It needs help with that one
An array type with a const element type is both a const qualified type (the const applies bidirectionally) and an array type.
So you should fix the specializations.