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;
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 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'm working on a project in C++ and am having trouble understanding what members of a template class get explicitly instantiated when I explicitly instantiate the template class. I've written the following file, which I then compile using Visual C++ 2008 Express Edition's Release configuration and then pop into a disassembler.
template<typename T> class test {
public:
template<typename T> test(T param) {
parameter = param;
};
~test() {};
int pop();
int push();
T parameter;
};
template<typename T> int test<T>::push() {return 1;}
template<typename T> int test<T>::pop() {return 2;}
template class test<int>;
int main() {
return 0;
}
Ignoring that this file doesn't really need templates for the moment, this compiles fine. I throw the exe into the disassembler and it tells me that test<int>::pop(void), test<int>::push(void), and test<int>::~test<int>(void) are functions in the exe, but I don't see the constructor. I know I can explicitly instantiate the constructor with
template test<int>::test(int);
which causes test<int>::test<int>(int) to appear in the disassembly as a function with the other ones. My understanding of explicit instantiation is that it is supposed to tell the compiler to instantiate all members of a template class for a given set of arguments, so why is it that the constructor is not explicitly instantiated along with all the other member functions?
When the constructor is a template member function, they are not instantiated unless explicitly used.
You would see the code for the constructor if you make it a non-template member function.
template<typename T> class test {
public:
/***
template<typename T> test(T param) {
parameter = param;
};
***/
test(T param) : parameter(param) {}
~test() {}
int pop();
int push();
T parameter;
};
Looking at a simple template scenario like this:
class A {
public:
int work();
};
class B {
public:
int work();
};
class ObjectManager {
public:
static void manage( A& obj );
// manage not defined for class B
};
template<class T>
doStuff( T t ) {
t.work();
....
ObjectManager::manage(t);
};
A a;
B b;
doStuf(a);
doStuff(b);
I am wondering, what is the cleanest way to implement a conditional call to ObjectManager::manage? The template function should determine in compile-time if ObjectManager::manage(T t) is defined for the given T and activate some lines of code only when it is. I guess there are solutions with some more nested template calls, but it would be the best for me just to keep the function in one piece.
Note that currently your class members are all private. They should be made public.
template<class T>
auto call_manage(T* t) -> decltype(ObjectManager::manage(*t)){
return ObjectManager::manage(*t);
}
void call_manage(...) {}
template<class T>
void doStuff( T t ) {
t.work();
//....
call_manage(std::addressof(t)); // smack whoever overloaded unary
// operator & in the head first
}
If the expression ObjectManager::manage(*t) is well-formed, substitution succeeds for the function template, which is always a better match than ..., so it is called. Otherwise, the do-nothing overload is the only viable function.
Demo.
For those who like references:
template<class T>
auto call_manage(T& t) -> decltype(ObjectManager::manage(t)){
return ObjectManager::manage(t);
}
template<class... T>
void call_manage(T&&...) {}
template<class T>
void doStuff( T t ) {
t.work();
//....
call_manage(t);
}
In this case, the single-argument overload is more specialized than the variadic version by the partial ordering rules for function templates, and is selected by overload resolution if both are equally viable. You can also make it take T&& t and call manage(std::forward<T>(t)), for perfect forwarding.
Demo.
just now I had to dig through the website to find out why template class template member function was giving syntax errors:
template<class C> class F00 {
template<typename T> bar();
};
...
Foo<C> f;
f.bar<T>(); // syntax error here
I now realize that template brackets are treated as relational operators. To do what was intended the following bizarre syntax is needed, cf Templates: template function not playing well with class's template member function:
f.template bar<T>();
what other bizarre aspects and gotcha of C++/C++ templates you have encountered that were not something that you would consider to be common knowledge?
I got tripped up the first time I inherited a templated class from another templated class:
template<typename T>
class Base {
int a;
};
template<typename T>
class Derived : public Base<T> {
void func() {
a++; // error! 'a' has not been declared
}
};
The problem is that the compiler doesn't know if Base<T> is going to be the default template or a specialized one. A specialized version may not have int a as a member, so the compiler doesn't assume that it's available. But you can tell the compiler that it's going to be there with the using directive:
template<typename T>
class Derived : public Base<T> {
using Base<T>::a;
void func() {
a++; // OK!
}
};
Alternatively, you can make it explicit that you are using a member of T:
void func {
T::a++; // OK!
}
This one got me upset back then:
#include <vector>
using std::vector;
struct foo {
template<typename U>
void vector();
};
int main() {
foo f;
f.vector<int>(); // ambiguous!
}
The last line in main is ambiguous, because the compiler not only looks up vector within foo, but also as an unqualified name starting from within main. So it finds both std::vector and foo::vector. To fix this, you have to write
f.foo::vector<int>();
GCC does not care about that, and accepts the above code by doing the intuitive thing (calling the member), other compilers do better and warn like comeau:
"ComeauTest.c", line 13: warning: ambiguous class member reference -- function
template "foo::vector" (declared at line 8) used in preference to
class template "std::vector" (declared at line 163 of
"stl_vector.h")
f.vector<int>(); // ambiguous!
The star of questions about templates here on SO: the missing typename!
template <typename T>
class vector
{
public:
typedef T * iterator;
...
};
template <typename T>
void func()
{
vector<T>::iterator it; // this is not correct!
typename vector<T>::iterator it2; // this is correct.
}
The problem here is that vector<T>::iterator is a dependent name: it depends on a template parameter. As a consequence, the compiler does not know that iterator designates a type; we need to tell him with the typename keyword.
The same goes for template inner classes or template member/static functions: they must be disambiguated using the template keyword, as noted in the OP.
template <typename T>
void func()
{
T::staticTemplateFunc<int>(); // ambiguous
T::template staticTemplateFunc<int>(); // ok
T t;
t.memberTemplateFunc<int>(); // ambiguous
t.template memberTemplateFunc<int>(); // ok
}
Out of scope class member function definition:
template <typename T>
class List { // a namespace scope class template
public:
template <typename T2> // a member function template
List (List<T2> const&); // (constructor)
…
};
template <typename T>
template <typename T2>
List<T>::List (List<T2> const& b) // an out-of-class member function
{ // template definition
…
}