My question is related to this one: How to publicly inherit from a base class but make some of public methods from the base class private in the derived class?, but my case is a little more complex as I want to change the access for overloaded/template functions:
template<typename T>
class Base
{
public:
void fun(int); //1
void fun(float); //2
void fun(T); //3
template<typename U> //4
void fun(U);
};
template<typename T1, typename T2>
class Derived : private Base<T1>
{
public:
//change access specifier here for:
//1 - make fun(int) available
//2 - fun(float) is really evil and it should not be accessible!
//3 - make fun(T1) == Base::fun(T) available
//4 - make template<typename U> void Base::fun(U) available
};
I've tried the method from previous answer to make some function public, but I get this error:
ISO C++11 does not allow access declarations; use using declarations instead
How can I use using to make only the selected functions (1, 3 and 4) available for users of Derived?
As Armen and Jarod pointed out, using will bring all fun's in the derived class. Jarod though had a great idea: delete the evil function! Combining their answers I got this:
template<typename T1, typename T2>
class Derived : private Base<T1>
{
public:
using Base<T1>::fun;
void fun(float) = delete;
};
which does exactly what I wanted originally!
You can either make all entities with the name fun available, or none of them. To do so, write:
public:
using Base::fun;
In your case, you have to forward manually as using works as a whole:
template<typename T1, typename T2>
class Derived : private Base<T1>
{
public:
void fun(int i) { Base<T1>::fun(i); }
// Don't show void fun(float); so fun(float) will call the template method
// or forbid fun(float) by deleting the function
// void fun(float) = delete;
void fun(T1 t) { Base<T1>::fun(t); }
template<typename U> void fun(U u) { Base<T1>::fun(u); }
};
Related
I created an abstract base class with two sub classes:
class Base {
public:
int a, b, c;
virtual void unreal() = 0;
};
class Sub1: public Base {
public:
virtual void unreal() {}
};
class Sub2: public Base {
public:
virtual void unreal() {}
};
I want to create a function that I can pass parameter of both types:
vector<Sub1> v1 and vector<Sub2> v2
into it, using something like:
Function(vector<Base&> v) {}
But it didn't work. So I want to know is there anyway to do it?
With C++20 you can achieve that with the following:
template<std::derived_from<Base> T>
void function(const std::vector<T>& v) {}
The above is using templates to accommodate any type of vector (by allowing the function to accept const std::vector<T>& where T is a template parameter). But to restrict T to be only derived of Base we add inside the template the restriction on T, requiring it to be std::derived_from<Base>.
Code: http://coliru.stacked-crooked.com/a/8aaa0c941fdc493e
Before C++20 it would require some more cumbersome SFINAE:
template<typename T, std::enable_if_t<std::is_base_of_v<Base, T>>* Dummy = nullptr>
void function(const std::vector<T>& v) {}
Code: http://coliru.stacked-crooked.com/a/0b7d98a84b6139b7
Yes, you can pass both vector<Sub1> and vector<Sub2> into a function by using a reference to vector<Base>:
void Function(vector<Base>& v) {}
This should work because Sub1 and Sub2 are derived classes from Base, and a reference to a derived class can be passed to a reference to its base class. However, the function will not be able to modify the objects in the vector as the objects are passed by reference to a const vector.
This has me wondering. Suppose I have :
class Base
{
public:
template<typename T>
void foo(T& varT)
{
//
}
template<typename T, typename U>
void foo(T& varT, U& varU)
{
//
}
};
class Child : public Base
{
public:
template<typename T, typename U, typename Z>
void foo(T& varT, U& varU, Z& varZ)
{
//
}
};
Now when I try this:
Child c;
char cVar;
int iVar;
float fVar;
c.foo(cVar);
c.foo<int>(cVar);
c.template foo<int>(cVar);
None of the calls work. They are always shadowed with error 'No matching member function for call'. Can anybody point me to a way to resolve this? I read in the standard that derived objects shadow template functions inherited but the standard explicitly said that the parameter list must be the same if they are shadowed.
Appreciate the help.
Hiding base members always happens when you have a name in a derived class that is present in a base class. The basic reason is that it is desirable to guard derived class uses against changes in the base class: assuming names from bases were not hidden, if a new overload in a base class is added a working look-up to a derived member may be hijacked to rather refer to the base class without any indication in the derived class that something may happen in the base class. If you mean to make the base members available, you can use a using declaration:
class Child : public Base
{
public:
using Base::foo; // declare that you want look up members from the base class
template<typename T, typename U, typename Z>
void foo(T& varT, U& varU, Z& varZ)
{
//
}
};
In your code you had three calls:
c.foo(cVar) works with the using declaration.
c.foo<int>(cVar) doesn't work even with the using declaration because you can't bind a non-const reference to int to a char lvalue. Using c.foo<char>(cVar) would work.
c.template foo<int>(cVar) suffers from the same problem. Since c is clearly not a dependent name, there is no need at all to use template in this context.
Without the using declaration you can call the member by qualifying the call explicitly, e.g.:
c.Base::foo(cVar);
You need this:
http://en.cppreference.com/w/cpp/language/using_declaration
Add to Child's definition:
using Base::foo;
For example, I have the next code:
template<typename T, typename T2>
class a
{
public:
using myfl_t = float;
a(myfl_t fl, double db) {}
virtual void f()
{
std::cout << "a::f()\n";
}
};
template<typename T>
class b : public a<T, int>
{
using base_t = a<T, int>;
using myfl_t = typename base_t::myfl_t;
public:
b(myfl_t fl, double db)
: base_t(fl, db) {}
void f() override
{
std::cout << "b::f()\n";
}
};
It seems that I can reuse the base class's myfl_t declaration only by duplicating using in the derived class.
Is there an easier way to do it?
myflt_t defined in class a is not visible in class b as explained here: https://eli.thegreenplace.net/2012/02/06/dependent-name-lookup-for-c-templates
You can bring myflt_t into class b by without the explicit re-declaration:
using typename base_t::myfl_t
You can drop the using in b and use this in the constructor:
b(typename a<T, int>::myfl_t fl, double db)
In any event, your current code seems fine to me. You aren't really duplicating anything here. Duplicating would be if you had to specify float again, which is not the case here, so it's fine.
See this for the reason why:
Why is the keyword "typename" needed before qualified dependent names, and not before qualified independent names?
This has me wondering. Suppose I have :
class Base
{
public:
template<typename T>
void foo(T& varT)
{
//
}
template<typename T, typename U>
void foo(T& varT, U& varU)
{
//
}
};
class Child : public Base
{
public:
template<typename T, typename U, typename Z>
void foo(T& varT, U& varU, Z& varZ)
{
//
}
};
Now when I try this:
Child c;
char cVar;
int iVar;
float fVar;
c.foo(cVar);
c.foo<int>(cVar);
c.template foo<int>(cVar);
None of the calls work. They are always shadowed with error 'No matching member function for call'. Can anybody point me to a way to resolve this? I read in the standard that derived objects shadow template functions inherited but the standard explicitly said that the parameter list must be the same if they are shadowed.
Appreciate the help.
Hiding base members always happens when you have a name in a derived class that is present in a base class. The basic reason is that it is desirable to guard derived class uses against changes in the base class: assuming names from bases were not hidden, if a new overload in a base class is added a working look-up to a derived member may be hijacked to rather refer to the base class without any indication in the derived class that something may happen in the base class. If you mean to make the base members available, you can use a using declaration:
class Child : public Base
{
public:
using Base::foo; // declare that you want look up members from the base class
template<typename T, typename U, typename Z>
void foo(T& varT, U& varU, Z& varZ)
{
//
}
};
In your code you had three calls:
c.foo(cVar) works with the using declaration.
c.foo<int>(cVar) doesn't work even with the using declaration because you can't bind a non-const reference to int to a char lvalue. Using c.foo<char>(cVar) would work.
c.template foo<int>(cVar) suffers from the same problem. Since c is clearly not a dependent name, there is no need at all to use template in this context.
Without the using declaration you can call the member by qualifying the call explicitly, e.g.:
c.Base::foo(cVar);
You need this:
http://en.cppreference.com/w/cpp/language/using_declaration
Add to Child's definition:
using Base::foo;
In the CRTP pattern, we run into problems if we want to keep the implementation function in the derived class as protected. We must either declare the base class as a friend of the derived class or use something like this (I have not tried the method on the linked article). Is there some other (simple) way that allows keeping the implementation function in the derived class as protected?
Edit: Here is a simple code example:
template<class D>
class C {
public:
void base_foo()
{
static_cast<D*>(this)->foo();
}
};
class D: public C<D> {
protected: //ERROR!
void foo() {
}
};
int main() {
D d;
d.base_foo();
return 0;
}
The above code gives error: ‘void D::foo()’ is protected with g++ 4.5.1 but compiles if protected is replaced by public.
It's not a problem at all and is solved with one line in derived class:
friend class Base< Derived >;
#include <iostream>
template< typename PDerived >
class TBase
{
public:
void Foo( void )
{
static_cast< PDerived* > ( this )->Bar();
}
};
class TDerived : public TBase< TDerived >
{
friend class TBase< TDerived > ;
protected:
void Bar( void )
{
std::cout << "in Bar" << std::endl;
}
};
int main( void )
{
TDerived lD;
lD.Foo();
return ( 0 );
}
As lapk recommended, problem can be solved with simple friend class declaration:
class D: public C<D> {
friend class C<D>; // friend class declaration
protected:
void foo() {
}
};
However, that exposes all protected/private members of derived class and requires custom code for each derived class declaration.
The following solution is based on the linked article:
template<class D>
class C {
public:
void base_foo() { Accessor::base_foo(derived()); }
int base_bar() { return Accessor::base_bar(derived()); }
private:
D& derived() { return *(D*)this; }
// accessor functions for protected functions in derived class
struct Accessor : D
{
static void base_foo(D& derived) {
void (D::*fn)() = &Accessor::foo;
(derived.*fn)();
}
static int base_bar(D& derived) {
int (D::*fn)() = &Accessor::bar;
return (derived.*fn)();
}
};
};
class D : public C<D> {
protected: // Success!
void foo() {}
int bar() { return 42; }
};
int main(int argc, char *argv[])
{
D d;
d.base_foo();
int n = d.base_bar();
return 0;
}
PS: If you don't trust your compiler to optimize away the references, you can replace the derived() function with the following #define (resulted in 20% fewer lines of disassembly code using MSVC 2013):
int base_bar() { return Accessor::base_bar(_instance_ref); }
private:
#define _instance_ref *static_cast<D*>(this) //D& derived() { return *(D*)this; }
After some I came with a solution that works event for private members of templated derived classes. It does not solves the problem of not exposing all the members of the derived class to the base, since it uses a friend declaration on the whole class. On the other hand, for the simple case, this does not requires repeating the base name, nor it's template parameters and will always work.
First the simple case when the derived is non-template. The base takes an additional void template parameter just to show that everything still works in the case of extra template parameters of the base. The only needed one, as per the CRTP, is the typename Derived.
//Templated variadic base
template <typename Derived, typename...>
struct Interface
{
using CRTP = Interface; //Magic!
void f() { static_cast<Derived*>(this)->f(); }
};
//Simple usage of the base with extra types
//This can only be used when the derived is NON templated
class A : public Interface<A, void>
{
friend CRTP;
void f() {}
};
The only thing needed for this to work is the using CRTP = Interface; declaration in the base and the friend CRTP; declaration in the derived.
For the case when the derived is itself templated the situation is trickier. It took me some time to come to the solution, and I'm sure it's still not perfect.
Most of the magic happens inside these templates:
namespace CRTP
{
template <template <typename, typename...> class _Base, typename _Derived, typename... _BaseArgs>
struct Friend { using Base = _Base<_Derived, _BaseArgs...>; };
template <template <typename, typename...> class _Base, typename ..._BaseArgs>
struct Base
{
template <template <typename...> class _Derived, typename... _DerivedArgs>
struct Derived : public _Base<_Derived<_DerivedArgs...>, _BaseArgs...> {};
};
}
Their usage is more or less straightforward. Two use the above templates several steps are needed.
First, when inheriting in the derived class the inherited-from base class, and it's optional parameters, needs to be given. This is done using CRTP::Base<MyBase, BaseOptional....>, where MyBase is the name of the class used for CRTP, and the BaseOptional... are template parameters that are passed to the base class as-is, directly after passing our derived class that is supplied in the next step. When the base class does not accepts any additional template parameters they can be omitted completely: CRTP::Base<MyBase>.
The next step is to introduce the derived class (the whole point of CRTP). This is done by following the above CRTP::Base<...> with a ::Derived<ThisDerived, DerivedOptional...>. Where ThisDerived is the class this is defined in, and DerivedOptional... are all the template parameters declared in this class'es template declaration. The optional parameters much be specified exactly as they appear in the class template declaration.
The last step is declaring the base class as a friend. This is done by declaring friend typename CRTP::Friend<MyBase, ThisDerived, BaseOptional...>::Base somewhere in the class. The BaseOptional... template perameters must be repeated exactly as they appear in the CRTP::Base<MyBase, BaseOptional...> that is inherited from.
Follows is an example of using a templated derived when the base does not depends on the templated types (but it still can take other template parameters, void in this example).
//Templated derived with extra, non-dependant types, passed to the base
//The arguments passed to CRTP::Base::Derived<, ARGS> must exactly match
// the template
template <typename T, typename... Args>
class B : public CRTP::Base<Interface, void>::Derived<B, T, Args...>
{
friend typename CRTP::Friend<Interface, B, void>::Base;
void f() {}
};
Next is an example for when the base depends on template parameters of the derived. The only difference from the previous example is the template keyword. An experiment shows that if the keyword is specified for the previous, non dependant, case the code also complies cleanly.
//Templated derived with extra dependant types passed to the base
//Notice the addition of the "template" keyword
template <typename... Args>
class C : public CRTP::Base<Interface, Args...>::template Derived<C, Args...>
{
friend typename CRTP::Friend<Interface, C, Args...>::Base;
void f() {}
};
Please note that these templates do not work for non-templated derived classes. I will update this answer when I find the solution, so a unified syntax could be used for all cases. The closest thing that can be done is just using some fake template parameter. Note that it still must be named and passed to the CRTP machinery. For example:
template <typename Fake = void>
class D : public CRTP::Base<Interface>::Derived<D, Fake>
{
friend typename CRTP::Friend<Interface, D>::Base;
void f() {}
};
Note that A, B, C & D are declared as class. That is, all their members are private.
Follows is some code that uses the above classes.
template <typename... Args>
void invoke(Interface<Args...> & base)
{
base.f();
}
int main(int, char *[])
{
{
A derived;
//Direct invocation through cast to base (derived.f() is private)
static_cast<A::CRTP &>(derived).f();
//Invocation through template function accepting the base
invoke(derived);
}
{
B<int> derived;
static_cast<B<int>::CRTP &>(derived).f();
invoke(derived);
}
{
C<void> derived;
static_cast<C<void>::CRTP &>(derived).f();
invoke(derived);
}
{
D<void> derived;
static_cast<D<>::CRTP &>(derived).f();
invoke(derived);
}
return 0;
}
The invoke free-standing templated function works for any class derived from the base.
Also shown is how to cast the derived to the base without the need to actually specify the name of the base.
Surprisingly, this does not depend on any system headers.
The full code is available here: https://gist.github.com/equilibr/b27524468a0519aad37abc060cb8bc2b
Comments and corrections are welcome.