I' ve got a template class :
template <class T>
class A
{
...
protected:
T m_value;
}
And i would like te make a template using this class for vectors:
template <class T>
class B:public A<std::vector<T>> //no need of space between >> (c++11)
{
void testSize()
{
if(m_value.size() > ...)
{
...
}
}
}
The compiler complain about : error: 'm_value' was not declared in this scope
is there a way i can do this or have i to recode this function for each std::vector type using directly the A class?
Thanks,
Edit:
I've tryed this:
template <class T>
class B:public A<std::vector<T>> //no need of space between >> (c++11)
{
void testSize()
{
if(m_value.size() > ...)
{
...
}
}
std::vector<T> m_value;
}
The compiler doesn't complain anymore but does the m_value called in class A function's refer to m_value of class B?
In your first example, m_value is a dependent name.
Just do this to correctly refer it from within B:
this->m_value.size()
That is, turn your if statement to:
if(this->m_value.size() > ...)
The code in the edit section is wrong instead. Class B and class A will refer respectively to their own copy of m_value.
Related
With a class defined as follows:
template <typename T>
class A {
private:
T a;
public:
A(T& a) : a_(a) { }
template <typename D>
void Eval(D& arg)
{
// ...
}
};
template A<int>;
I want to explicitly instantiate one instance of the class, and I want this class to have one explicit instantiation of Eval. The intention here is to get a member function pointer that avoids ambiguity:
auto eval_ptr = &A<int>::Eval;
The ambiguity is not coming from anything to do with template instantiation of the class, it's caused by Eval also being a templated function.
&A<int>::Eval does not point to a function, it points to a template. And there is just no such type as a "pointer to a template".
If you want a pointer to A<int>::Eval, you need to specify D as well.
auto eval_ptr = &A<int>::Eval<int>; works just fine for example.
Addendum: Pointers-to-templates do exist in the grammatical sense, but there is no type an object can have to hold one of them. They must be immediately casted/decayed to a specific overload in order to be used, which doesn't come into play here since you want to store it in an auto.
For example: The following is fine because there's clearly only one "version" of Eval that can be meant:
void bar(void (A<int>::*arg)(int&)) {}
void foo() {
bar(&A<int>::Eval);
}
The very simple solution was specifying both template parameters:
template <typename T>
class A
{
private:
T a;
public:
A(T &a) : a_(a) {}
template <typename D>
void Eval(D &arg)
{
arg+=1;
}
};
int main()
{
auto p = &A<int>::Eval<int>;
}
I need to build my code in MSVC(C++98). I declare a template class with template class parameter. At result I am getting an error during compilation at MSVC:
error C2977: 'Set': too many template arguments
Gcc builds this code well.
You can try it by yourself:
https://godbolt.org/z/YJXLX7
here you are this code:
#include <iostream>
#include <vector>
class Iterator
{
public:
virtual int size() = 0;
};
template <template<typename> class TContainer, class TType>
class IteratorCollectionTest
: public Iterator
{
public:
virtual int size() { m_collection.size(); }
private:
TContainer<TType> m_collection;
};
template<typename TItem>
class Set
{
public:
Set();
Iterator* createIterator();
int size();
protected:
class SetInstance;
private:
SetInstance* m_instance;
};
template<typename TItem>
class Set<TItem>::SetInstance
{
public:
Iterator* createIterator() { return new IteratorCollectionTest<Set, TItem>(); }
int size() { return m_vec.size(); }
public:
std::vector<TItem> m_vec;
};
template<typename TItem>
Set<TItem>::Set()
: m_instance(new SetInstance())
{
}
template<typename TItem>
Iterator* Set<TItem>::createIterator()
{
return m_instance->createIterator();
}
template<typename TItem>
int Set<TItem>::size()
{
return m_instance->size();
}
int main()
{
Set<int> m_serr;
Iterator* iter = m_serr.createIterator();
}
what am I doing wrong?
Can anybody help me?
Class templates have a special member, called the injected class name. Inside the scope of the class template, the template name stands for the current specialization. It does not stand for the template.
new IteratorCollectionTest<Set, TItem>() appears inside the scope of the class template Set. So MSVC assumes the Set argument does not refer to the template. It assumes that the name refers to the specialization, the type that is Set<TItem>. And therefore passes a class name where a template name is expected.
It's the behavior mandated by C++98. And that behavior has since been amended in C++11, where the template name appearing as a template argument does not refer to the injected class name. In C++11 and later mode, GCC would accept the code. But when forcing C++98 mode, it complains too.
The workaround is to qualify the name.
Iterator* createIterator() { return new IteratorCollectionTest<::Set, TItem>(); }
Since ::Set is a fully qualified name, it can refer only to the template that is at namespace scope.
I can't seem to call a method of a base class without scoping to the base class, and it seems that this is because I have overloaded the method. If I do not overload the method then the compiler doesn't complain. Here's an example of what I'd like to do:
struct BaseClass {
template <typename T> T& foo(T& t) {
return t;
}
};
class ChildClass: public BaseClass {
public:
// The presence of this template causes compiler confusion
template <class T> T& foo(T& t, int szl) {
return t;
}
template <class T> int bar(T& t) {
// But if I scope this as BaseClass::foo(...) it's all good
return foo(t);
}
};
int main() {
int t = 1;
ChildClass c;
c.bar(t);
}
If in bar(...) I call BaseClass::foo(...) the compiler does not complain, but I don't see any ambiguity here and so I'm confused as to why I'd need to do this.
When the compiler tries to match a function name with a function, it does so in two steps. In the first step it finds all the functions that match the given name. If it finds more than one function, it tries the logic of overload resolution to find the best matching function.
In the first step, if the compiler finds a name in the class, it stops looking for functions of the same name in base classes. In your case, since it finds a foo in ChildClass, it stops searching for functions named foo in BaseClass. However, the only matching foo does not match the call and the compiler reports an error.
How to resolve the problem:
Use the method you described in your post. Call BaseClass::foo(...).
Bring all the foo from BaseClass into the scope of ChildClass.
class ChildClass: public BaseClass {
public:
using BaseClass::foo;
template <class T> T& foo(int baz, T& t, int szl) {
return t;
}
template <class T> int bar(T& t) {
return sizeof(foo(1, t)); // Should work.
}
};
From the C++ standard 3.3.10 paragraph 1 :
A name can be hidden by an explicit declaration of that same name in
a nested declarative region or derived class
ChildClass::foo shadows the definition of BaseClass::foo. All you need to bring it into scope is a using directive:
class ChildClass: public BaseClass {
public:
using BaseClass::foo;
template <class T> T& foo(int baz, T& t, int szl);
};
You need a using, like:
using BaseClass::foo;
I can't seem to call a method of a base class without scoping to the base class, and it seems that this is because I have overloaded the method. If I do not overload the method then the compiler doesn't complain. Here's an example of what I'd like to do:
struct BaseClass {
template <typename T> T& foo(T& t) {
return t;
}
};
class ChildClass: public BaseClass {
public:
// The presence of this template causes compiler confusion
template <class T> T& foo(T& t, int szl) {
return t;
}
template <class T> int bar(T& t) {
// But if I scope this as BaseClass::foo(...) it's all good
return foo(t);
}
};
int main() {
int t = 1;
ChildClass c;
c.bar(t);
}
If in bar(...) I call BaseClass::foo(...) the compiler does not complain, but I don't see any ambiguity here and so I'm confused as to why I'd need to do this.
When the compiler tries to match a function name with a function, it does so in two steps. In the first step it finds all the functions that match the given name. If it finds more than one function, it tries the logic of overload resolution to find the best matching function.
In the first step, if the compiler finds a name in the class, it stops looking for functions of the same name in base classes. In your case, since it finds a foo in ChildClass, it stops searching for functions named foo in BaseClass. However, the only matching foo does not match the call and the compiler reports an error.
How to resolve the problem:
Use the method you described in your post. Call BaseClass::foo(...).
Bring all the foo from BaseClass into the scope of ChildClass.
class ChildClass: public BaseClass {
public:
using BaseClass::foo;
template <class T> T& foo(int baz, T& t, int szl) {
return t;
}
template <class T> int bar(T& t) {
return sizeof(foo(1, t)); // Should work.
}
};
From the C++ standard 3.3.10 paragraph 1 :
A name can be hidden by an explicit declaration of that same name in
a nested declarative region or derived class
ChildClass::foo shadows the definition of BaseClass::foo. All you need to bring it into scope is a using directive:
class ChildClass: public BaseClass {
public:
using BaseClass::foo;
template <class T> T& foo(int baz, T& t, int szl);
};
You need a using, like:
using BaseClass::foo;
I am trying to create a class Info<P,S> which holds a pointer to another object of type Info<S,P>. I have the following code.
template <class P, class S>
class Info {
….
public:
Info(…, Info<S,P>* parentInfo) : …, parentInfo(parentInfo)
{}
…
private:
Info<S, P> *parentInfo;
};
….
typedef Info<ActualP, ActualS> OneInfo;
typedef Info<ActualS, ActualP> OtherInfo;
…
OtherInfo* parentInfo =…;
OneInfo info(…, parentInfo);
This is not compiling and saying the constructor is not a valid one (at the call).
I suppose this would cause an infinite recursion while trying to resolve. Am I right? What are the alternatives to implement this intent of referencing Info<S,P> from Info<P,S>?
Use typename to refer a type that depends of a template parameter:
template <class T>
class Info
{
public:
Info() : parentInfo(NULL) {}
Info(Info<typename T> *info) :
parentInfo(info)
{
}
private:
Info<typename T> *parentInfo;
};
int _tmain(int, _TCHAR**)
{
Info<int> parent;
Info<int> child(&parent);
}