Given the following code:
template<typename T>
class A
{
public:
T t;
};
class B
{
public:
void foo(int i) {}
template<typename T>
void foo(A<T>& a) {}
};
int main()
{
A<int> a;
B b;
b.foo(a );
b.foo(a.t);
}
This compiles and works fine; the correct overloaded versions of B::foo() are chosen and called for a and a.t.
Now I introduce a new class C which derives from B and move the template version of ::foo() out of B and into C:
template<typename T>
class A
{
public:
T t;
};
class B
{
public:
void foo(int i) {}
};
class C: public B
{
public:
template<typename T>
void foo(A<T>& a) {}
};
int main()
{
A<int> a;
C c;
c.foo(a ); // Fine
c.foo(a.t); // Error
}
And now the code won't compile anymore. Visual Studio 2005 is stating:
error C2784: 'void C::foo(A<T> &)' : could not deduce template argument for 'A<T> &' from 'int'
In fact, calling C::foo() with any int value results in this error. It almost seems like the method overload for int is being hidden by the template overload.
Why is this happening? Is it some issue with Visual Studio 2005's compiler? Unfortunately, I cannot test it on any other compiler right now.
Any information is appreciated.
It almost seems like the method overload for int is being hidden by the template overload.
Exactly! You need to add a using declaration to class C:
class C: public B
{
public:
using B::foo;
template<typename T>
void foo(A<T>& a) {}
};
When you declare a member function in a derived class, all member functions in the base class with the same name are hidden. See ยง3.3.10/3 of ISO/IEC 14882:2011:
The declaration of a member in a derived class (Clause 10) hides the declaration of a member of a base class of the same name; see 10.2.
It's hiding, no overloading. Use
class C: public B
{
public:
using B::foo;
template<typename T>
void foo(A<T>& a) {}
};
Correct, the base function is hidden. That's actually the proper term for it. Add using B::foo; to the class definition of C to unhide it.
Related
I try to initialize a static member of a CRTP base class. The base class holds a static template member of the derived class, while the derived class defines other data members. I want to statically initialize this variable. In code, a minimal example would be the following:
template<typename DERIVED>
class base {
public:
static DERIVED x;
};
class derived : public base<derived>
{
public:
int a;
};
int base<derived>::x {0};
int main()
{}
However, the above does not compile, but gives the error message error: specializing member 'base<derived>::x' requires 'template<>' syntax.
How can I get the static initialization to work?
The correct syntax is:
template <class T>
class base {
public:
static T x;
};
template <class T>
T base<T>::x{};
Note that you can't initialize x to a specific integer value, since then your base class won't compile when DERIVED is e.g. an std::string.
You probably also want your inheritance to be explicitly public or private. I.e.:
class derived : public base<derived> {
public:
int a;
};
Edit: To specialize x and it's initialization for specific types T, you have to specialize base itself. I.e.:
class A;
template <>
class base<A> {
public:
static int x;
};
// Note missing "template <>" here.
int base<A>::x{ 5 };
class A : public base<A> { };
This seems rather cumbersome, since you need to already forward declare A in this case before declaring the specialization. To me it feels you might want to rethink your design. Is this really required or is there a simpler way to accomplish what you want?
I have found the static initializer trick, which works in the above setting, too. It was described here and here. In the above context, it would be as follows:
#include <iostream>
template<typename DERIVED>
class base {
public:
static inline DERIVED x;
};
class derived : public base<derived>
{
public:
int a;
struct static_initializer {
static_initializer()
{
derived::x.a = 1;
}
};
static inline static_initializer static_initializer_;
};
int main()
{
std::cout << derived::x.a << "\n";
}
The above output the value 1.
Note: this works with C++17.
Consider the following:
template<typename T>
class A
{
public:
A(int a)
{}
A() = delete;
};
class B
{
public:
B()
{
A<int> a;
}
};
Of course this code does not compile because class B's constructor is attempting to default-construct a class A object and I've explicitly deleted that constructor. All well and good.
However, if I make B a class template
template<typename T>
class A
{
public:
A(int a)
{}
A() = delete;
};
template<typename T>
class B
{
public:
B()
{
A<int> a;
}
};
then the code does compile and it seems I can now default-construct an instance of class A.
Why is this? What am I missing?
Thanks.
D'oh! It appears that the compiler doesn't see the error until it attempts to instantiate a class from the template.
Actually trying to create an object of type B<> generates the expected error.
Sorry if I wasted your time.
This question already has an answer here:
SFINAE method completely disables base class's template method in clang
(1 answer)
Closed 3 years ago.
Given a base class and a derived class, which both provide conditionally enabled operators for specific parameter types using SFINAE:
#include <type_traits>
class Base
{
public:
template<class T, std::enable_if_t<std::is_scalar_v<T>>* = nullptr>
void operator>>(T& value) {
}
};
class Derived: public Base
{
public:
using Base::operator>>;
template<class T, std::enable_if_t<!std::is_scalar_v<T>>* = nullptr>
void operator>>(T& value) {
}
};
int main(int argc, char *argv[])
{
int foo;
Base base;
base >> foo; // this works
Derived derived;
derived >> foo; // this doesn't work, the operator from the base class is not considered
}
then calling an operator defined in the base class on an instance of the derived class will not work, even though it should have been made visible by the appropriate using Base::operator>>; declaration. Why? How can the operator from the base class be made usable without verbosely repeating the declaration/definition?
The problem does not occur if the operator in question is not a template in the base class.
Edit: Tested with msvc 15.9.7 as well as clang.
I think the problem here is that a using declaration only brings the declarations of functions and function templates into a derived class that have signatures which are not overridden by members of the derived class [namespace.udecl]/15. So this code should indeed not compile.
Use free functions instead of class members to fix the problem:
#include <type_traits>
class Base
{
public:
template<class T, std::enable_if_t<std::is_scalar_v<T>>* = nullptr>
friend void operator>>(Base&, T& value) {
}
};
class Derived: public Base
{
public:
template<class T, std::enable_if_t<!std::is_scalar_v<T>>* = nullptr>
friend void operator>>(Derived&, T& value) {
}
};
int main()
{
int foo;
Base base;
base >> foo;
Derived derived;
derived >> foo;
}
live example here
In a derived class If I redefine/overload a function name from a Base class,
then those overloaded functions are not accessable/visible to derived class.
Why is this??
If we don't overload the oveloaded function from the base class in derived class
then all the overloaded versions of that function are available to derived class
objects, why is this??
what is the reason behind this. If you explain this in compiler and linker level
that will be more helpful to me. is it not possible to support this kind of scinario??
Edited
For examble:
class B
{
public:
int f() {}
int f(string s) {}
};
class D : public B
{
public:
int f(int) {}
};
int main()
{
D d;
d.f(1);
//d.f(string); //hidden for D
}
Now object 'd' can't access f() and f(string).
TTBOMK this doesn't have a real technical reason, it's just that Stroustrup, when creating the language, considered this to be the better default. (In this it's similar to the rule that rvalues do not implicitly bind to non-const references.)
You can easily work around it be explicitly bringing base class versions into the derived class' scope:
class base {
public:
void f(int);
void g(int);
};
class derived : public base {
public:
using base::f;
void f(float);
void g(float); // hides base::g
};
or by calling the explicitly:
derived d;
d.base::g(42); // explicitly call base class version
The functions are available, you just need to call them explicitly:
struct A {
void f(){}
};
struct B : public A {
void f() {}
};
int main() {
B b;
b.f(); // call derived function
b.A::f(); // call base function
}
I am not sure how to ask this, but hopefully someone will understand. Lets say I have 3 different classes. Class A, Class B and Class C. Class C should take either Class A or Class B as a parameter in the constructor and store it in a private variable.
This is easy with overloaded constructors. My question is how can Class C automagically use the correct class depending on what constructor was used? (Note these 2 classes are similar, but come from different libraries and thus no shared base class). Is this possible with templates? I do not have a lot of experience with templates.
You can do it quite easy with templates:
class A;
class B;
template<class AorB>
class C
{
public:
C(AorB aorb)
: aorb_(aorb)
{ }
private:
AorB aorb_;
};
What this does is that inside the class C the identifier AorB can be used as any other class, in fact it doesn't even have to be an instance of A or B but can be any class.
Can be used like this:
A myA;
B myB;
C<A> myCWithA(myA);
C<B> myCWithB(myB);
There is however one thing you have to remember when creating classes using templates: The specification and implementation can no longer be split into separate header and source files. All of the code have to be available in the header file.
The syntax of the member functions are also a little different.
Example:
template<class T>
class C
{
public:
...
void someFunction();
};
template<class T>
C<T>::someFunction()
{
...
}
Yes, this is possible with templates:
#include <iostream>
template<class T>
class C {
public:
C(T const& ref) : ref(ref) {}
void doStuff() const {
ref.doStuff();
}
private:
T ref;
};
class A {
public:
void doStuff() const {
std::cout << "A::doStuff" << std::endl;
}
};
class B {
public:
void doStuff() const {
std::cout << "B::doStuff" << std::endl;
}
};
int main() {
C<A> foo((A()));
foo.doStuff();
C<B> bar((B()));
bar.doStuff();
}