How do I specialize this template member function? - c++

I have this setup:
class DontUse;
template<class T,class U = DontUse, class V = SomeStandardType>
class Foo
{
public:
void bar(U &uh);
};
When U is set to DontUse, I want bar to be an empty function. In all other cases, I want bar to have some implementation. I tried doing this using specialization, but this code (which I realize is somehow incorrect) doesn't compile:
template<class T,class V> void Foo<T,DontUse,V>::bar(DontUse &none){}
template<class T,class U,class V> void Foo<T,U,V>::bar(U &uh)
{
//do something here
}
The error message is this (MSVC10):
1>path_to_project: error C2244: 'Foo<T,U,V>::bar' : unable to match function definition to an existing declaration
and it points to the line of the first template specialization.
How do I do this correctly?
Here's the actual code, although it's reduced to the minimalist part that's relevant:
struct DontUse;
template<typename Derived, typename Renderer = DontUse, typename TimeType = long>
class Gamestate
{
public:
void Render(Renderer &r);
};
template<typename Derived, typename TimeType> void Gamestate<Derived, DontUse,TimeType>::Render( DontUse){}
template<typename Derived, typename Renderer, typename TimeType> void Gamestate<Derived,Renderer,TimeType>::Render(Renderer &r)
{
static_cast<Derived*>(this)->Render(r);
}

You cannot specialize individual members of a template. You have to specialize the class itself:
class DontUse;
template<class T, class V>
class Foo<T, DontUse, V>
{
   public:
     void bar(DontUse)
{ }
};

I recommend to just use this:
#include <type_traits>
template <class A, class B, class C>
struct S
{
void foo(B& b)
{
static_assert(!std::is_same<U, DontUse>::value, "Bad Boy!");
}
};
Or, if you really want a empty function, just use an if.
#include <type_traits>
template <class A, class B, class C>
struct S
{
void foo(B& b)
{
if(!std::is_same<U, DontUse>::value)
{
//all code goes here
}
}
};

It doesn't work like that. A member function of a class template is not itself a separate template, and cannot be specialized (partially or fully) independently of the class template.
You need to define a partial specialization of the class template Foo, give it a bar member function, and define that.

Related

C++ - Template subclass inherits from multiple template classes

I am creating a simple class named HashMap:
template <typename K,typename V> class HashMap{
.
.
.
public:
class Hashable;
I created another class:
template<typename T> class Stack;
Now I must create a new class (NewStackClass), which extends Stack and HashMap<K,V>::Hashable.
Objects of this class are meant to be instantiated when K=Stack/NewStackClass.
Example:
HashMap<NewStackClass<int>,int> map;
//T=int;K=NewStackClass<int>;V=int;
or:
HashMap<Stack<char>,int> map;
//T=char;K=Stack<char>;V=int;
How can I obtain this? Also, I want to split class declaration from its implementation.
I already tried with this:
template <typename B, typename C>
template <typename A> class NewStackClass : public Stack<A>, public HashMap<B,C>::Hashable{
virtual int hashCode() const;
bool operator==(const MyStack<A>& stack);
};
but it didn't work:
[Error] too many template-parameter-lists
Any help is appreciated.
EDIT
Creating NewStackclass:
template <typename StackType,typename HashMapValue> class MyStack : public NewStackClass<StackType>, public HashMap<Stack<StackType>,HashMapValue>::Hashable{
virtual int hashCode() const {
return 1;
}
bool operator==(const NewStackClass<StackType,HashMapValue>& stack){
return true;
}
};
Let's get in the private area of HashMap class:
private:
int hash(const Hashable& key) const{
return (31*17 +key.hashCode()) % TABLE_SIZE;
}
Doing this in main.cpp:
HashMap<NewStackClass<int,int>,int> map1;
NewStackClass<int,int> stack;
map1.put(stack,0);
Brings out this error:
[Error] no matching function for call to "HashMap<NewStackClass<int, int>, int>::hash(const NewStackClass<int, int>&)"
Error comes from this:
[Note] no known conversion for argument 1 from 'const NewStackClass' to 'const HashMap, int>::Hashable&'
Your code contains a syntactical flaw. You may only have a single template parameter list for your class.
merge
template <typename B, typename C>
template <typename A> class NewStackClass ...
to this
template <typename B, typename C, typename A>
class NewStackClass ...
to make it compile.
Also you did not provide information on what MyStack is supposed to be. I just assume that you meant to write Stack instead.
You should also think about whether your class NewStackClass really needs three template arguments or if there are actually only two distinct ones.
Judging by your question, your might want to do:
template <typename K, typename V>
class NewStackClass : public Stack<K>, public HashMap<Stack<K>,V>::Hashable {
instead.
Fixed Code (Syntax Only)
template <typename K,typename V>
class HashMap {
public:
class Hashable {
};
};
template<typename T> class Stack {
};
template <typename B, typename C, typename A>
class NewStackClass : public Stack<A>, public HashMap<B,C>::Hashable {
virtual int hashCode() const;
bool operator==(const Stack<A>& stack);
};

Use a template template parameter with CRTP in a Concept

I want to write a concept that tests for inheritance from a base class.
My Base class is publicly inherited by Derived classes, using CRTP.
This code works fine:
#include <type_traits>
namespace NS
{
template<typename D>
class Base {
// ...
};
class Derived : public Base<Derived>
{
public:
constexpr Derived() = default;
// ...
};
}
template<typename D>
concept bool inheritsFromB() {
return std::is_base_of<NS::Base<D>, D>::value;
}
template<inheritsFromB b>
void myFunct() {};
int main() {
constexpr auto d = NS::Derived();
using dType = typename std::decay<decltype(d)>::type;
myFunct<dType>();
}
I hit a problem if I want to template Derived. Is this possible?
namespace NS
{
template<typename D, typename T>
class Base { ... };
template<typename T>
class Derived : public Base<Derived<T>, T>
{ // ...
// probably some using declaration for T?
};
}
template<template <typename> class D>
concept bool inheritsFromB() {
return std::is_base_of<NS::B<D<T>,T>, D<T>::value;
}
...
the obvious problem being that I have no T in my concept declaration.
Moreover, I'm pretty sure I can't declare
template<template <typename> class D, typename T>
concept bool inheritsFromB() {
...
}
because a concept requires one template parameter.
Edit - the Working Paper P0121R0 lists in section 8.3.5, p23, template<typename T, typename U> concept bool C3 = true;. Consequently, wherever I read a concept can take only one parameter was either outdated, wrong, or I read it lacking care. end edit
Can I access the other type(s) T that I need here? Is there an alternative way (it seems to me like the template type D would carry the information of what it's type T is, but I also can't use using T = typename D<T>::valueType;, because I need the T to specific the type of D<T>...)
I suspect the following trait should work:
#include <type_traits>
#include <utility>
namespace NS
{
template <typename D, typename T>
class Base {};
template <typename T>
class Derived : public Base<Derived<T>, T> {};
}
namespace detail
{
template <typename T, template <typename> typename D>
std::true_type is_derived_from_base(const ::NS::Base<D<T>,T>*);
std::false_type is_derived_from_base(void*);
}
template <typename T>
using is_derived_from_base = decltype(detail::is_derived_from_base(std::declval<T*>()));
template <typename T>
concept bool inheritsFromB()
{
return is_derived_from_base<T>{};
}
DEMO (without concepts)

template named constructor struct omit typename

I have a class looking like
template <typename T> class CClass
{
public:
struct NamedCtor;
CClass(T a, T b, T c);
private:
// data members
};
tepmlate <typename T> CClass<T>::NamedCtor : CClass<T> { NamedCtor(T x) : CClass(x, x, x) {}; };
With CClass<T>::NamedCtor() as named constructor.
This is perfectly usable if I know the template parameter when using with CClass<int>::NamedCtor(3).
But if I do not know the template parameter here, for example when I'm in a template function, I have to write something like typename CClass<T>::NamedCtor(3) with the template parameter T of the function.
Is there any way to bypass this typename as I don't really like it?

How do we typedef or redefine a templated nested class in the subclass?

Consider the following:
template <typename T>
class Base {
public:
template <typename U>
class Nested { };
};
template <typename T>
class Derived : public Base<T> {
public:
//How do we typedef of redefine Base<T>::Nested?
using Base<T>::Nested; //This does not work
using Base<T>::template<typename U> Nested; //Cannot do this either
typedef typename Base<T>::template<typename U> Nested Nested; //Nope..
//now we want to use the Nested class here
template <typename U>
Class NestedDerived : public Nested { };
//or like this:
Nested<int> nestedVar; // obviously does not work
};
How to use the templated Nested class in the Derived class? Is this possible to do in current version of C++ standard?
Actually using works as advertised, it just doesn't get rid of the dependent-name issue in the template and it can't currently alias templates directly (will be fixed in C++0x):
template <class T>
struct Base {
template <class U> struct Nested {};
};
template <class T>
struct Derived : Base<T> {
using Base<T>::Nested;
// need to prefix Nested with template because
// it is a dependent template:
struct X : Base<T>::template Nested<int> {};
// same here:
template<class U>
struct Y : Base<T>::template Nested<U> {};
// data member, typename is needed here:
typename Base<T>::template Nested<int> data;
};
void f() {
Derived<int>::Nested<int> n; // works fine outside
}
There is another possible gotcha when using Derived<T>::Nested in templates, but again that is a dependent-name issue, not inheritance-related:
template<class T>
void g() {
// Nested is a dependent type and a dependent template, thus
// we need 'typename' and 'template':
typedef typename Derived<T>::template Nested<int> NestedInt;
}
Just remember that names that depend on template arguments have to be
prefixed with typename if its a dependent type: typename A<T>::B
directly prefixed with template if its a dependent template: A<T>::template f<int>()
both if both: typename A<T>::template B<int>
typename is illegal in base-class-lists: template<class T> struct A : B<T>, C<T>::template D<int> {};
This seems to work:
(EDIT: added some more lines to show the first template statement. And thanks to Samir Talwar for correcting my formatting!)
template <typename T, typename U>
class Derived : public Base<T> {
public:
typedef typename Base<T>::template Nested<U> Nested;
class NestedDerived : public Nested { };
Nested nestedVar;
};
Try this:
template <typename T>
class Base {
public:
template <typename U>
class Nested { };
};
template <typename T>
class Derived : public Base<T> {
public:
//How do we typedef of redefine Base<T>::Nested?
//using Base<T>::Nested; //This does not work
//using Base<T>::template<typename U> Nested; //Cannot do this either
//typedef typename Base<T>::template<typename U> Nested Nested; //Nope..
//now we want to use the Nested class here
template <typename U>
class NestedDerived : public Base<T>::template Nested<U> { };
};
int main()
{
Base<int>::Nested<double> nested;
Derived<int>::NestedDerived<double> nested_derived;
return 0;
}
Compiled fine using gcc 4.3.3 on slackware 13
I'm still not 100% sure what you want, but you could try.
This compiled on Visual Studio
template <typename T>
class Base {
public:
template <typename U>
class Nested { };
};
template <typename T>
class Derived : public Base<T> {
public:
//now we want to use the Nested class here
template <typename U>
class NestedDerived : public Nested<U> { };
};
int _tmain(int argc, _TCHAR* argv[])
{
Base<int>::Nested<double> blah2;
Derived<int>::NestedDerived<int> blah;
return 0;
}

C++ partial method specialization

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.