I have code such as
template <class T> class Widget
{
void fun() {}
}
//Okay: specialization of a member function of widget
template <> void Widget<char>:: fun()
{
void fun() {}
}
But, below is error as I am been told. But not understand why.
template<class T, class U> class Gadget
{
void fun() {}
}
//Error! cannot partially specialize a member function of Gadget
template<class U> void Gadget<char,U>::fun()
{
..specialized implementation
}
Why is the second wrong? how to change it to make it right?
thanks!!!!
It is impossible to partially specialize just one single member function, you have to partially specialize the whole class. That's how things work in C++.
The reason is that you cannot have partially specialized functions, and member functions are themselves functions. By partially specializing the whole class, the member functions will "look" like templates with fewer types (in that partial specialized class).
Why you cannot have partially specialized functions is another story, and I don't have a good answer/understanding why is this enforced.
About making it work, why don't you partially specialize the class, then re-define only the function that you need.
One approach is to move that single function to a helper class template, which can be partially specialized:
template<class T, class U> class Gadget;
template<class T, class U>
struct Gadget_fun
{
static void do_it(Gadget<T,U>* This) {}
};
template<class T, class U> class Gadget
{
friend class Gadget_fun<T,U>;
void fun() { Gadget_fun<T,U>::do_it(this); }
};
template<class U>
struct Gadget_fun<char, U>
{
static void do_it(Gadget<char,U>* This)
{
//..specialized implementation
}
};
This way you don't have to duplicate all the other members as you would to specialize Gadget itself.
Related
I would like to have a function overload for each type of a variadic template class. Is that possible ?
template<typename ...args>
class Example {
virtual void doSomething(args(0) arg) { ... }
virtual void doSomething(args(1) arg) { ... }
/// etc... implementations are the same, but I need access to the type
}
I tried using fold expressions but I'm pretty sure I'm not on the right track. Because I need the functions to be virtual, I cannot declare them as template<typename T> virtual void doSomething(T arg) because, well, template virtual functions aren't allowed.
You can derive the class from a templated pack of instantiations of a base class template that defines one virtual function with its single template parameter as the function parameter type.
The derived class then holds the function overloads for each template argument type, that are all virtual.
template<typename arg>
class Base {
virtual void doSomething(arg arg) {}
};
template<typename ...args>
class Example : public Base<args>... {};
IMO, C++ template rules seem too restrictive and compiler implementation defined. But here I have a specific behavior I've had a hard time wrapping my head around.
In the following problem, I consciously try to avoid explicitly specializing the parent class.
The problem is that, I can partially specialize a member, but can't specialize it fully. Which is really counter intuitive, because you can easily add a dummy template to a fully specialized template and make it partially specialized. What's going on here?
This matters because, as we know, you can't specialize member functions without specializing the class as well (which can be seen as a combination of this problem, need to be partially specialized, and the fact that c++ doesn't allow partially specialized functions. I don't know whether these are related but at least they're consistent), thus if you want a functionoid in your class that you can specialize you're stuck with using functors. And on top of that you need to add a dummy template parameter just to make that work!
This works:
template <class T>
class A
{
template<typename Y, typename Z>
struct C{
void operator()(int x);
};
template<typename Z>
struct C<int, Z>{
void operator()(int x);
};
};
template <class T>
template <typename Z>
void A<T>::C<int, Z>::operator()(int x){
}
But this doesn't:
template <class T>
class A
{
template<typename Y>
struct C{
void operator()(int x);
};
template<>
struct C<int>{
void operator()(int x);
};
};
template <class T>
template <>
void A<T>::C<int>::operator()(int x){
}
Sean F. in the comments pointed out that it's hard for a compiler to choose a specialization. But the problem here is that partially specializing doesn't make that problem go away. So that can't be the answer.
As a general rule, template function specialization is a bad idea. Use overloads or tag dispatching. For example:
template<class T>struct tag_t{};
template<class T>
auto foo(T& t){ return foo( tag_t<T>{}, t ); }
now we can use overloads to dispatch:
void foo( tag_t<int>, int& i ){ i+=3; }
template<class T>
void foo( tag_t<T>, T& t ){ t*=2; }
there is no specialization going on here. We use overload resolution rules to pick the implementation. And this works fine with members.
We only use specialization on top-level classes. Even there I am often tempted to pick implementations by tag dispatch and use of decltype, as overload resolution often gives better pattern matching.
If you really need a member class, replace your member class with a top-level class and some friend declarations.
template<class T, class Y>
struct A_C;
template <class T>
class A
{
template<class T0, class Y0>
friend class A_C<T0, Y0>;
template<class Y>
using C=A_C<T,Y>;
};
template<class T, class Y>
struct A_C {
// implementation of A::C
};
now you have pretty unrestriced specialization of A_C here. None of your problems.
I have a template that inherits from another template, with itself as the second template's template parameter. The inherited template defines a static function:
template<class T> class A
{
public:
static void foo();
};
template<class T> class B : public A<B>
{
};
Now I want to implement the static function for the class A specialized with B, but with B not specialized. But I can't figure out how to declare the template. I'm not even sure if this is possible. My first try was:
template<class T> void A<B<T>>::foo()
{
}
But this gives the error:
"Nested name specifier 'A<B<T>>::" for declaration does not refer into a class, class template or class template partial specialization"
I've tried different things like adding "template<>" in front but none of those worked. I am able to compile this:
template<> void A<B<int>>::foo()
{
}
As well as this:
template<class T> void A<T>::foo()
{
}
Is this an attempt at partial specialization? My first impression is no (there are no templates with multiple parameters where I want to specialize one of them). Rather, I want to specialize a template with another template that is not specialized. Is this possible, and if so what is the proper syntax?
This is indeed partial specialization. You cannot partially specialize just a method, you must partially specialize the whole class. See this answer. You might try implementing foo in a separate helper struct and partially specializing that struct instead.
Here is an example using a helper struct.
#include <iostream>
template<class T> struct t_helper
{
static void foo()
{
std::cout << "Not B<T>\n";
}
};
template<class T> class A
{
public:
static void foo() {
t_helper<T>::foo();
}
};
template<class T> class B {};
// Specialize the behavior of A<T>::foo() for all B types
template<class T>
struct t_helper<B<T>>
{
static void foo()
{
std::cout << "Is B<T>\n";
}
};
int main()
{
A<int>::foo(); // Prints "Not B<T>\n"
A<B<int>>::foo(); // Prints "Is B<T>\n"
return 0;
}
Given the following definitions:
template <typename T>
class A {
public:
void f();
};
template <typename T>
void
A<T>::f()
{}
template <typename T>
class B {};
How would I partially specialize A<B<T>>::f, i.e. f for some B<T>? I'm basically looking for the right magic to substitute the ??? below
template <???>
void
A<B<T>>::f()
{}
You can have an explicit specialization, from [temp.expl.spec]:
An explicit specialization of any of the following:
— ...
— member function of a class template
— ...
can be declared by a declaration introduced by template<>
That is:
template <>
void A<B<int>>::f() {
std::cout << "B\n";
}
But you cannot have a partial specialization of a member function of a class template. You would have to partially specialize the entire class:
template <typename T>
class A<B<T>> {
public:
void f() {
std::cout << "B\n";
}
// ... all other members you want in A<B<T>> ...
};
You cannot partially specialize a member function (nor in fact any function). You need to partially specialize the whole class:
template<typename T>
class A<B<T>>
{
// implement member functions for this specialization here
};
If you must have:
template <typename T>
void A<B<typename T>>::f() {}
then your only choice is to partially specialize A.
template <typename T> class A<B<T>>
{
public:
void f();
};
C++11 has Alias Templates, allowing you do do something like:
template<T>
using AB = A<B<T>>;
Then you can refer to AB<T> instead of A<B<T>>.
Unfortunately, you can't use that for specialization..
So seems to me the answer to your question is: You can't do that, but it's a shame.
Is there a partial specialization for template class method?
template <class A, class B>
class C
{
void foo();
}
it doesn't work to specialize it like this:
template <class A> void C<A, CObject>::foo() {};
Any help?
If you are already have specialized class you could give different implementation of foo in specialized class:
template<typename A, typename B>
class C
{
public:
void foo() { cout << "default" << endl; };
};
template<typename A>
class C<A, CObject>
{
public:
void foo() { cout << "CObject" << endl; };
};
To specialize member function in Visual C++ 2008 you could make it template too:
template<typename A, typename B>
class C
{
template<typename T>
void foo();
template<>
void foo<CObject>();
};
The solution above seems to will be available only in future C++ Standard (according to draft n2914 14.6.5.3/2).
I think there is a misunderstanding there.
There are two kinds of templates:
the template classes
the template methods
In your example, you have a template class, which of course contains some methods. In this case, you will have to specialize the class.
template <class A>
class C<A,CObject>
{
void foo() { ... } // specialized code
};
The problem in your example is relatively simple: you define the method foo for the specialization C but this specialization has never been declared beforehand.
The problem here is that you have to fully specialize your C class (and thus copying a lot of data). There are a number of workarounds.
Inheritance (Composition ?): do all the common work in a base class, then have the C class inherits and specialize as appropriate
Friend: instead of having the 'foo' method being a member of C, define it as a friend free functions and specialize only this method
Delegation: have your 'foo' method call another method 'bar', which is a free function, and specialize 'bar' appropriately
Which in code gives:
// 1- Inheritance
template <class A, class B>
class CBase
{
// Everything that does not require specialization
};
template <class A, class B>
class C: public CBase<A,B>
// depending on your need, consider using another inheritance
// or even better, composition
{
void foo(); // generic
};
template <class A>
class C<A,CObject> : public CBase<A,CObject>
{
void foo(); // specialized
};
// 2- Friend
// note the change in signature:
// - now you need to pass the attributes to be changed
// - the last parameter helps differentiating the overload
// as there is no specialization for functions
template <class A, class B> void foo(Arg1&, Arg2&, const B&);
template <class A> void foo(Arg1&, Arg2&, const CObject&);
template <class A, class B>
class C
{
friend template <class, class> foo;
};
// 3- Delegation
// same signature as foo in (2)
template <class A, class B> void bar(Arg1&, Arg2&, const B&);
template <class A> void bar(Arg1&, Arg2&, const CObject&);
template <class A, class B>
class C
{
void foo() { bar(member1, member2, B()); }
};
Hope it clarifies, and helps!
No, there is no partial function template specialization in C++0x to be added.
As correctly mentioned above, with regards to function templates basically 2 things were done:
default template arguments were made available;
variadic templates were introduced.
So as before, workarounds should be used to "emulate" partial function templates specialization.
Since the class is the template, you need to specialize that:
template <class A>
class C<A, CObject>
{
void foo() { ... }
}
If I remember correctly, you cannot make partial template specialization for functions. Not sure whether it is included in C++0X
Update:
(Awaiting confirmation) As noted in the comments, partial template specialization of functions is possible in C++0X.
A method template may delegate to (static) methods of partially specialized classes or structs. Template parameters in the outer class are not helpful for answering the question.
class ClassWithSpecializedMethodEmulation
{
private:
template <typename A, typename B> struct Calculator;
public:
template <typename A, typename B> A evaluate(A a, B b)
{
return Calculator<A,B>::evaluate(a,b);
}
private:
template <typename A, typename B> struct Calculator
{
// Common case: multiply
static A evaluate(A a, B b)
{
return (A)(a*b);
}
};
// with double argument a do something else
template <typename B> struct Calculator<double, B>
{
static double evaluate(double a, B b)
{
return (double)(a - b);
}
};
};
In case the method requires access to class members, struct Calculator additionally must be friend of ClassWithSpecializedMethodEmulation and get a this-pointer passed.