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
}
Related
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
I am looking for help with templates. I need to create function in template what will be reacting differently on a specific type.
It could looks like this:
template <typename T>
class SMTH
{
void add() {...} // this will be used if specific function isn't implemented
void add<int> {...} // and here is specific code for int
};
I also tried to use typeid and swich through types in a single function, but doesn't work for me.
You really don't want to be doing this branching at runtime, with typeid.
We want this code:
int main()
{
SMTH<int>().add();
SMTH<char>().add();
return 0;
}
To output:
int
not int
There are lot of ways I can think of to achieve this (all at compile time and half of them requires C++11):
Specialize the whole class (if it has only this add function):
template <typename T>
struct SMTH
{
void add() { std::cout << "not int" << std::endl; }
};
template <>
struct SMTH<int>
{
void add() { std::cout << "int" << std::endl; };
};
Specialize only the add member function (recommended by #Angelus):
template <typename T>
struct SMTH
{
void add() { std::cout << "not int" << std::endl; }
};
template <> // must be an explicit (full) specialization though
void SMTH<int>::add() { std::cout << "int" << std::endl; }
Note that if you instantiate SMTH with cv-qualified int, you'll get the not int output for above approaches.
Use the SFINAE idiom. There are few variants of it (default template argument, default function argument, function return type), and the last one is the one that fits here:
template <typename T>
struct SMTH
{
template <typename U = T>
typename std::enable_if<!std::is_same<U, int>::value>::type // return type
add() { std::cout << "not int" << std::endl; }
template <typename U = T>
typename std::enable_if<std::is_same<U, int>::value>::type
add() { std::cout << "int" << std::endl; }
};
The main benefit is that you can make the enabling condition complex, e.g. using std::remove_cv to choose the same overload regardless of cv-qualifiers.
Tag dispatching - chooses the add_impl overload based on if the instantiated tag inherits from A or B, in this case std::false_type or std::true_type. You still use template specialization or SFINAE, but this time it's done on a tag class:
template <typename>
struct is_int : std::false_type {};
// template specialization again, you can use SFINAE, too!
template <>
struct is_int<int> : std::true_type {};
template <typename T>
struct SMTH
{
void add() { add_impl(is_int<T>()); }
private:
void add_impl(std::false_type) { std::cout << "not int" << std::endl; }
void add_impl(std::true_type) { std::cout << "int" << std::endl; }
};
This can of course be done without defining the custom tag class, and the code in add will look like this:
add_impl(std::is_same<T, int>());
I don't know if I mentioned them all, and I don't know why I attempted to, either. All you have to do now is to choose the one that fits the use the best.
Now, that I see, that you also wanted to check if a function exists. This is already long, and there's an existing QA about that.
In the following snippit, is the template<> optional for the specialization? Is there any difference whether I include it or not? My first instinct was to include it as it more-or-less signifies that it is a specialization. It compiles both ways under both g++ 4.9.2 and Intel 16
#include <vector>
#include <iostream>
template<typename T>
struct PrintMe
{
static void Print(const T & t)
{
std::cout << "In general templated struct: " << t << "\n";
}
};
template<> // <--- optional?
template<typename T>
struct PrintMe<std::vector<T>>
{
static void Print(const std::vector<T> & t)
{
std::cout << "In general specialization for vector: " << t.size() << "\n";
for(const auto & it : t)
std::cout << " " << it << "\n";
}
};
int main(void)
{
PrintMe<int>::Print(5);
PrintMe<double>::Print(5);
PrintMe<std::vector<float>>::Print({10,20,30,40});
return 0;
}
Note: Out of curiosity, I tried adding multiple template<>. Ie,
template<>
template<>
template<>
template<typename T>
struct PrintMe<std::vector<T>>
This still compiles with Intel, but not with g++. Not sure what that means, but it's interesting.
Note 2: Wow, this is very similar to a question of mine from 5 years ago: Templated class specialization where template argument is a template . There it was mentioned as redundant syntax.
Given the definition of the class template,
template<> // <--- optional?
template<typename T>
struct PrintMe<std::vector<T>> { ... };
is not valid.
You need to remove that line and use:
template<typename T>
struct PrintMe<std::vector<T>> { ... };
there are ways to look at templates and template specialization that will paint a better picture and make the whole thing clearer.
For me in this case the easier way to look at this is not to think of
template<typename T>
struct PrintMe<std::vector<T>> { ... };
as a specialization of
template<typename T>
struct PrintMe { ... };
but as a different class template altogether, it just happen to be that the two have similarly named methods.
I'm trying to specialize a member function template for two different types of classes as follows:
#include <iostream>
#include <boost/utility/enable_if.hpp>
struct Wibble
{
static const bool CAN_WIBBLE = true;
};
struct Wobble
{
static const bool CAN_WIBBLE = false;
};
struct Foo
{
//template<typename T> // Why isn't this declaration sufficient?
//void doStuff();
template<typename T>
typename boost::enable_if_c<T::CAN_WIBBLE,void>::type
doStuff();
template<typename T>
typename boost::enable_if_c<!T::CAN_WIBBLE,void>::type
doStuff();
};
template<typename T>
typename boost::enable_if_c<T::CAN_WIBBLE,void>::type
Foo::doStuff()
{
std::cout << "wibble ..." << std::endl;
}
template<typename T>
typename boost::enable_if_c<!T::CAN_WIBBLE,void>::type
Foo::doStuff()
{
std::cout << "I can't wibble ..." << std::endl;
}
int main()
{
Foo f;
f.doStuff<Wibble>();
f.doStuff<Wobble>();
}
Whereas GCC 4.8.2 compiles the code, VS .NET 2008 spits out the error message:
error C2244: 'Foo::doStuff' : unable to match function definition to an existing declaration
definition
'boost::enable_if_c<!T::CAN_WIBBLE,void>::type Foo::doStuff(void)'
existing declarations
'boost::enable_if_c<!T::CAN_WIBBLE,void>::type Foo::doStuff(void)'
'boost::enable_if_c<T::CAN_WIBBLE,void>::type Foo::doStuff(void)'
I suggest to use tag dispatching: https://ideone.com/PA5PTg
struct Foo
{
template<bool wibble>
void _doStuff();
public:
template<typename T>
void doStuff()
{
_doStuff<T::CAN_WIBBLE>();
}
};
template<>
void Foo::_doStuff<true>() { std::cout << "wibble ..." << std::endl; }
template<>
void Foo::_doStuff<false>() { std::cout << "I can't wibble ..." << std::endl; }
You can't partially specialize (member) function templates. End of story.
Even if you could, you should have had a SFINAE-friendly primary template. In pseudo code:
template<typename T, typename Enable> void doStuff();
template<typename T> void doStuff<T, typename boost::enable_if_c<T::CAN_WIBBLE,void>::type>()
{ std::cout << "wibble ..." << std::endl; }
template<typename T> void doStuff<T, typename boost::enable_if_c<!T::CAN_WIBBLE,void>::type>()
{ std::cout << "I can't wibble ..." << std::endl; }
You could still use this technique if you are ready class templates (as functors or just types defining non-template methods...).
As a rule of thumb, for function templates, overload resolution provides static polymorphism that removes the need for partial specialization. See
GotW #49 Template Specialization and Overloading
Why Not Specialize Function Templates?
Both by Herb Sutter
How can I specialize or overload function func so that specialization handles all instances of MyClass? Assume func is a librarian function (like std::swap for example) so I can't change func, and I can't replace or wrap it, I have to specialize it.
#include <iostream>
template<typename T>
class MyClass
{
};
template<typename T>
void func(const T&)
{
std::cout << "Default" << std::endl;
}
// I don't want to copy this stuff for every instance of MyClass
template<>
void func<MyClass<int>>(const MyClass<int>&)
{
std::cout << "Specialization" << std::endl;
}
int main(int, char**)
{
func(int(0)); // "Default"
func(MyClass<int>()); // "Specialization"
func(MyClass<double>()); // "Default" but I want "Specialization" here
return 0;
}
Here are a few examples of what you can do.
template<typename T>
void func(const T&)
{
std::cout << "Default" << std::endl;
}
template<template<typename> class A , typename B>
void func(const A<B>&)
{
std::cout << "Overload All templated classes with one templated argument B" << std::endl;
}
template<typename T>
void func(const MyClass<T>&)
{
std::cout << "Overload Myclass with some templated argument T" << std::endl;
}
If you cannot change the global func in anyway and still want to avoid copying one way is to use macro to automate the repeatative stuff for you.
#define Specialize(TYPE) \
template<> \
void func<MyClass<TYPE>>(const MyClass<TYPE>&) \
{ \
std::cout << "Specialization" << std::endl; \
}
Specialize(int);
Specialize(double);
If you have freedom to alter MyClass<T>, then place all the common functionality of MyClass<T> into a common non-template base class:
template<typename T>
class MyClass<T> : public MyClassBase // <---- a common base class
...
And simply overload or specialize func() only for MyClassBase:
void func(const MyClassBase&)
{
std::cout << "Specialization" << std::endl;
}