Template argument deduction in partial specialization - c++

#include <iostream>
using namespace std;
template <typename T> class A{
public:
void test() { cout << "normal" << endl;}
};
//template <typename T> class A<T&>{
//public:
// void test() { cout << "&" << endl;}
//};
template <typename T> class A<T&&>{
public:
void test() { cout << "&&" << endl;}
};
int main(){
A<int&> a;
a.test();
}
The output is normal suggesting the ordinary (non-specialised) template was chosen. This may be seem obvious straight away since int & is supplied as a template argument and the only available specialisation is one that takes an rvalue reference. But why is it that the second template specialisation cannot be selected by choosing T = int& in which case reference collapsing causes T&& to become int&?

Related

Why no overload chosen on forward reference for function templates?

Snippet:
#include <iostream>
template<typename T>
struct Printer{};
template<typename T>
void test(T&&)
{
std::cout << "Primary template called\n";
}
template<typename T>
void test(Printer<T>&&)
{
std::cout << "Specialized template called\n";
}
int main()
{
auto t = Printer<int>{};
test(0);
test(t);
}
Here is the demo
Why is two times Primary template called printed?
If one removes the forward reference from the second template, then the Printer overload is chosen.
Why is it not chosen with &&?
Forwarding reference only works for T&&, not C<T>&& nor const T&&.
test(0); // Call test(T&&) with T=int
test(t); // Call test(T&&) with T=Printer<int>&

How do member variables work with specialized class templates?

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
}

Override template function with abstract class

I have created a template function, defined below.
template<class T>
void func(T t){ /* do stuff */ }
I would like to overload this template in the event that T inherits from an abstract class I made.
class A {
public:
virtual void doStuff() = 0;
};
class B : public A {
virtual void doStuff(){ /* do stuff */ }
}
I have tried using template specialization (below), but it still was using the original definition.
template<>
void func(A& a){ /* do different stuff */ } // Not called by func(B())
I tried overloading it as well, and while this worked with ints, it isn't working with my base class.
func(int i){ /* do stuff with i */ } // Called by func(3)
func(A& a){ /* do different stuff */ } // Not called by func(B())
I'm guessing this has to do with C++ not wanting to implicitly cast my instance of B to an A and reference it, but I haven't been able to find anything explaining how I can fix this behavior. Since A has a pure virtual function, I can't just define func(A a). Any help would be appreciated.
Here is an example in which the behavior I'm experiencing can be reproduced.
#include <iostream>
template<class T>
void func(T t){
std::cout << "Template function called!" << std::endl;
}
class A {
public:
virtual void doStuff() = 0;
};
class B : public A{
public:
virtual void doStuff(){};
};
template<>
void func(const A& a){
std::cout << "Specialized template called!" << std::endl;
}
void func(const A& a){
std::cout << "Overload called!" << std::endl;
}
int main(){
B b{};
func(b);
return 0;
}
If you have access to C++17, then you can create a public overload that will forward to the correct function:
namespace detail {
template<class T>
void func(T t) {
std::cout << "Template function called!" << std::endl;
}
void func(A& a){
std::cout << "Overload called!" << std::endl;
}
}
template<class T>
void func(T& t) {
if constexpr (std::is_base_of_v<A, T>) {
detail::func(static_cast<A&>(t));
} else {
detail::func(t);
}
}
int main() {
B b;
func(b);
}
Otherwise you can use tag dispatching or SFINAE:
Tag dispatching:
template<class T>
void func(T t, std::false_type) {
std::cout << "Template function called!" << std::endl;
}
void func(A& a, std::true_type) {
std::cout << "Other function called!" << std::endl;
}
template<class T>
void func(T& t) {
func(t, std::is_base_of<A, T>{});
}
SFINAE:
template<class T,
std::enable_if_t<std::is_base_of_v<A, T>>* = nullptr>
void func(T t) {
std::cout << "Template function called!" << std::endl;
}
template<class T,
std::enable_if_t<!std::is_base_of_v<A, T>>* = nullptr>
void func(T& t) {
std::cout << "Other function called!" << std::endl;
}
C++20 solution
You can run the code here.
Using Concepts from C++20, we can write an inherits_from concept, and use that. Concepts allow us to constrain a template so that it only applies in situations where an expression is true.
The concept looks like this:
#include <type_traits>
template<class Derived, class Base>
concept derived_from = std::is_base_of_v<Base, Derived>;
Then, we can write the generic template and the constrained template:
struct MyBase{};
struct MyDerived : MyBase{};
// This is the generic template; using auto here is valid in C++20
void do_thing(auto const& thing) {
std::cout << "Doing thing on regular type\n";
}
//This is the template that acts on classes derived from MyBase
void do_thing(derived_from<MyBase> const& x) {
std::cout << "Doing thing on MyBase\n";
}
Because the second function declares T as following the concept inherits_from, it's more specialized, so for types that actually inherit from MyBase, it'll be selected over the generic template:
int main() {
do_thing(10); // Prints "Doing thing on regular type"
do_thing(MyBase()); // Prints "Doing thing on MyBase"
do_thing(MyDerived()); // Prints "Doing thing on MyBase"
}
C++17 solution
You can run the code here.
We can emulate the behavior of concepts using SFINAE, although this requires modifying the generic template so that it'll by ignored if T extends MyBase. The key to using SFINAE is to trigger a substitution failure if a condition is false, resulting in that overload being ignored.
In order to trigger a substitution failure, add a defaulted template argument at the end of the list of template parameters. In our case, it looks like this:
template<
class T,
// This defaulted argument triggers the substitution failure
class = std::enable_if_v</* condition */>>
In our code,
- The generic overload will be disabled if T extends MyBase
- The constrained overload will be disable if T doesn't extend MyBase
It looks like this:
struct MyBase {};
struct MyDerived : MyBase {};
template<
class T,
class = std::enable_if_t<!std::is_base_of_v<MyBase, T>>>
void do_thing(T const&) {
std::cout << "Doing thing on regular type\n";
}
// This overload is *disabled* if T doesn't inherit from MyBase
template<
class T,
// We have to have an additional defaulted template argument to distinguish between the overloads
class = void,
class = std::enable_if_t<std::is_base_of_v<MyBase, T>>>
void do_thing(T const& x) {
std::cout << "Doing thing on MyBase\n";
}
Despite the weird declaration, we can still use do_thing as though it were a regular function:
int main() {
do_thing(10);
do_thing(MyBase());
do_thing(MyDerived());
}
Backporting things to C++11
You can run the code here.
We only have to make a few minor changes to backport things to C++11. Basically,
is_base_of_v<MyBase, T> has to be replaced by is_base_of<MyBase, T>::value, and
enable_if_t</* condition */> has to be replaced by typename enable_if</* condition */>::type
B b;
func((A&)b);
I don't think you can pass a temporary here. You cannot cast B() to 'A&' because it is an rvalue and casting it to const A& makes the template version a better match.
Another options (on top of other answers) using c++11 - explicitly removing the template version if T is a subtype of B:
template<class T>
typename std::enable_if<!std::is_base_of<A, T>::value>::type
func(T& t){
std::cout << "Template function called!" << std::endl;
}
void func(const A& a){
std::cout << "Overload called!" << std::endl;
}
int main(){
func(B());
}

Templates Calling Each Other's Functions

So, I have a fairly simple set of templates that I want to use together, but the compiler keeps telling me that B::a has incomplete type. Everything is forward declared, but it still doesn't work...
#include <iostream>
using namespace std;
template <typename T> class A;
template <typename T> class B;
template <typename T>
class A{
public:
void ATestFunction();
void CallBFunction();
protected:
B<T> b;
};
template <typename T>
class B{
public:
void BTestFunction();
void CallAFunction();
protected:
A<T> a;
};
template <typename T>
void A<T>::ATestFunction(){
cout << "A was used for a function call" << endl;
}
template <typename T>
void B<T>::BTestFunction(){
cout << "B was used for a function call" << endl;
}
template <typename T>
void A<T>::CallBFunction(){
b.BTestFunction();
}
template <typename T>
void B<T>::CallAFunction(){
a.ATestFunction();
}
int main()
{
A<int> dragons;
dragons.CallBFunction();
return 0;
}
I ask this because I had run into some difficulty programming some array type classes that depend on each other (implementing a two dimensional array that can be accessed like this: [][]), but this problem happened and threw a gear in the works. I made this testing program, but it still fails. I've tried both MinGW 4.7.2 and GNU g++ on Linux, and each gave me the same problem.
The core of the issue can be seen in this piece of code:
template <typename T>
class A{
B<T> b;
};
template <typename T>
class B{
A<T> a;
};
C++ is a language with value semantics, that means that B<T> b; represents an object of type B<T> (rather than a reference, like in Java or C# with reference types). That is, A<T> contains a B<T>. Now if you look at the definition of the B template you see that in turn it contains an A<T> sub object. This is basically impossible, as A<T> cannot possibly contain an object that contains A<T>. What would be the size of an A<T> object?
Without knowing the real problem to solve, I won't venture to recommend an approach, but you can consider using pointers (A<T> would contain a pointer to B<T>, not a full B<T> sub object; or similarly, B<T> could contain a pointer to A<T>; or both), or references. But it might also be the case that a deeper redesign could make more sense.
Even if you used pointers, that could not work. That would basically trigger an infinite loop of A´s and B´s being created
A creates B creates A creates B creates A...
this would work.
#include <iostream>
using namespace std;
template<typename T> class A;
template<typename T> class B;
template<typename T>
class A
{
public:
A()
{
b = new B<T>(this);
}
A(B<T>* pb)
{
b = pb;
}
void ATestFunction()
{
cout << "A was used for a function call" << endl;
}
void CallBFunction()
{
b->BTestFunction();
}
protected:
B<T>* b;
};
template<typename T>
class B
{
public:
B()
{
a = new A<T>(this);
}
B(A<T>* pa)
{
a = pa;
}
void BTestFunction()
{
cout << "B was used for a function call" << endl;
}
void CallAFunction()
{
a->ATestFunction();
}
protected:
A<T>* a;
};
int main()
{
A<int> dragons;
dragons.CallBFunction();
B<int> bdragons;
bdragons.CallAFunction();
return 0;
}
or maybe just using static functions
#include <iostream>
using namespace std;
template<typename T> class A;
template<typename T> class B;
template<typename T>
class A
{
public:
static void ATestFunction()
{
cout << "A was used for a function call" << endl;
}
void CallBFunction();
};
template<typename T>
class B
{
public:
static void BTestFunction()
{
cout << "B was used for a function call" << endl;
}
void CallAFunction();
};
template<typename T>
void A<T>::CallBFunction()
{
B<int>::BTestFunction();
}
template<typename T>
void B<T>::CallAFunction()
{
A<int>::ATestFunction();
}
int main()
{
A<int> dragons;
dragons.CallBFunction();
B<int> bdragons;
bdragons.CallAFunction();
return 0;
}

C++ compiler error on template specialization

I would like to specialize a template method for a class C that is itself
templated by an int parameter.
How do I do this?
template <int D=1>
class C {
static std::string foo () { stringstream ss; ss << D << endl; return ss.str();}
};
template <class X>
void test() { cout << "This is a test" << endl;}
template <>
template <int D>
void test<C<D> > () {cout << C<D>::foo() << endl;}
The specialization for test() fails with "Too many template parameter lists in declaration of void test()".
Function template partial specialization is not allowed. Do
template <int D>
void test () {cout << C<D>::foo() << endl;}
You don't want the first template<> on your partial specialisation of test<C<D>>. Moreover, you can only partially specialise class templates, not function templates. Something like this might work:
template <class X>
struct thing
{
static void test() { cout << "This is a test" << endl;}
};
template <int D>
struct thing<C<D>>
{
static void test() {cout << C<D>::foo() << endl;}
};
If your function template took an argument, and used that to infer the template argument, then you could get a similar effect using overloading, something like:
template <class X>
void test(const X&) { cout << "This is a test" << endl;}
template <int D>
void test(const C<D>&) {cout << C<D>::foo() << endl;}
test(3); // calls first version
test(C<3>()); // calls second version