As the title says, I'd like to prevent implicit conversions from a derived class to its base class while retaining public inheritance. I do not have access to the base class implementation. Example:
// I cannot edit anything in the `thirdparty` namespace
namespace thirdparty {
struct base { void f(); };
}
// I do not know what `T` is in advance
template <typename T>
struct derived : T { };
int main()
{
derived<thirdparty::base> d;
d.f(); // I want 'f' to be exposed via public inheritance
thirdparty::base b = d; // I want this to be a compiler error
}
I tried deleting conversion operators as follows:
template <typename T>
struct derived : T {
operator const T&() const& = delete;
operator T&() & = delete;
operator T&&() && = delete;
};
However, that had no effect. Is there any way to achieve what I want?
My problem is that I can't chain methods from Derived class when I already used Base class methods. I tried to mix topmost answers from Returning a reference to the derived class from a base class method and CRTP and multilevel inheritance, but the problem is one of them is always returning the same object, the other is returning void. I want Base class being able to be inherited by any other class.
[The naive solution to this problem is to make a() virtual and override it in class Derived. But what if Base is inherited by 100 other classes and have 100 other methods to override? This is not scaling good.]
[The other naive solution is to call methods from Derived class first, then from Base, but... just no]
So, is it possible to somehow compile the following snippet in native C++? (I am not interested in boost solutions). It would be ideal if main()'s code wouldn't change.
#include <iostream>
#include <type_traits>
template <typename T = void>
class Base
{
public:
T& a();
};
class Derived : public Base<Derived>
{
public:
Derived& b() {std::cout << "b\n"; return *this;}
};
int main()
{
Base base;
base
.a()
;
Derived derived;
derived
.a()
.b()
;
return 0;
}
template <typename T>
T& Base<T>::a()
{
std::cout << "a\n";
if(std::is_same<T, void>::value)
{
return *this;
}
else
{
return static_cast<T&>(*this);
}
}
If only i could write template <typename T = Base> class Base { ... :)
Not sure if it is what you want, but with C++17 and if constexpr, you might do:
template <typename T = void>
class Base
{
public:
auto& a()
{
std::cout << "a\n";
if constexpr (std::is_same_v<T, void>) {
return *this;
} else {
return static_cast<T&>(*this);
}
}
};
Demo
Before, you might use specialization.
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.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why do I have to access template base class members through the this pointer?
I have a class hierarchy like the following:
template<typename T>
class Base {
protected:
T t;
};
template<typename T>
class Derived: public Base<T> {
public:
T get() { return t; }
};
int main() {
Derived<int> d;
d.get();
}
The problem is that the protected member variable t is not found in the Base class. Compiler output:
prog.cpp: In member function 'T Derived<T>::get()':
prog.cpp:10:22: error: 't' was not declared in this scope
Is that correct compiler behavior or just a compiler bug? If it is correct, why is it so? What is the best workaround?
Using fully qualified name works, but it seems to be unnecessarily verbose:
T get() { return Base<T>::t; }
To use members from template base classes, you have to prefix with this->.
template<typename T>
class Derived: public Base<T> {
public:
T get() { return this->t; }
};
I am trying to use template meta-programming to determine the base class. Is there a way to get the base class automatically without explicitly specializing for each derived class?
class foo { public: char * Name() { return "foo"; }; };
class bar : public foo { public: char * Name() { return "bar"; }; };
template< typename T > struct ClassInfo { typedef T Base; };
template<> struct ClassInfo<bar> { typedef foo Base; };
int main()
{
ClassInfo<foo>::Base A;
ClassInfo<bar>::Base B;
std::cout << A.Name(); //foo
std::cout << B.Name(); //foo
}
for right now any automatic method would need to select the first declared base and would fail for private bases.
It's possible with C++11 and decltype. For that, we'll exploit that a pointer-to-member is not a pointer into the derived class when the member is inherited from a base class.
For example:
struct base{
void f(){}
};
struct derived : base{};
The type of &derived::f will be void (base::*)(), not void (derived::*)(). This was already true in C++03, but it was impossible to get the base class type without actually specifying it. With decltype, it's easy and only needs this little function:
// unimplemented to make sure it's only used
// in unevaluated contexts (sizeof, decltype, alignof)
template<class T, class U>
T base_of(U T::*);
Usage:
#include <iostream>
// unimplemented to make sure it's only used
// in unevaluated contexts (sizeof, decltype, alignof)
template<class T, class R>
T base_of(R T::*);
struct base{
void f(){}
void name(){ std::cout << "base::name()\n"; }
};
struct derived : base{
void name(){ std::cout << "derived::name()\n"; }
};
struct not_deducible : base{
void f(){}
void name(){ std::cout << "not_deducible::name()\n"; }
};
int main(){
decltype(base_of(&derived::f)) a;
decltype(base_of(&base::f)) b;
decltype(base_of(¬_deducible::f)) c;
a.name();
b.name();
c.name();
}
Output:
base::name()
base::name()
not_deducible::name()
As the last example shows, you need to use a member that is actually an inherited member of the base class you're interested in.
There are more flaws, however: The member must also be unambiguously identify a base class member:
struct base2{ void f(){} };
struct not_deducible2 : base, base2{};
int main(){
decltype(base_of(¬_deducible2::f)) x; // error: 'f' is ambiguous
}
That's the best you can get though, without compiler support.
My solutions are not really automatic, but the best I can think of.
Intrusive C++03 solution:
class B {};
class A : public B
{
public:
typedef B Base;
};
Non-intrusive C++03 solution:
class B {};
class A : public B {};
template<class T>
struct TypeInfo;
template<>
struct TypeInfo<A>
{
typedef B Base;
};
I am not aware of any base-class-selecting template, and I'm not sure one exists or is even a good idea. There are many ways in which this breaks extensibility and goes against the spirit of inheritance. When bar publicly inherits foo, bar is a foo for all practical purposes, and client code shouldn't need to distinguish base class and derived class.
A public typedef in the base class often scratches the itches you might need to have scratched and is clearer:
class foo { public: typedef foo name_making_type; ... };
int main() {
Foo::name_making_type a;
Bar::name_making_type b;
}
What's with the base class? Are you a .NET or Java programmer?
C++ supports multiple inheritance, and also does not have a global common base class. So a C++ type may have zero, one, or many base classes. Use of the definite article is therefore contraindicated.
Since the base class makes no sense, there's no way to find it.
I am looking for a portable resolution for similar problems for months. But I don't find it yet.
G++ has __bases and __direct_bases. You can wrap them in a type list and then access any one of its elements, e.g. a std::tuple with std::tuple_element. See libstdc++'s <tr2/type_traits> for usage.
However, this is not portable. Clang++ currently has no such intrinsics.
With C++11, you can create a intrusive method to always have a base_t member, when your class only inherits from one parent:
template<class base_type>
struct labeled_base : public base_type
{
using base_t = base_type; // The original parent type
using base::base; // Inherit constructors
protected:
using base = labeled_base; // The real parent type
};
struct A { virtual void f() {} };
struct my_class : labeled_base<A>
{
my_class() : parent_t(required_params) {}
void f() override
{
// do_something_prefix();
base_t::f();
// do_something_postfix();
}
};
With that class, you will always have a parent_t alias, to call the parent constructors as if it were the base constructors with a (probably) shorter name, and a base_t alias, to make your class non-aware of the base class type name if it's long or heavily templated.
The parent_t alias is protected to don't expose it to the public. If you don't want the base_t alias is public, you can always inherit labeled_base as protected or private, no need of changing the labeled_base class definition.
That base should have 0 runtime or space overhead since its methods are inline, do nothing, and has no own attributes.
Recently when I reading Unreal Engine source code, I found a piece of code meet your requirement.
Simplified code is below:
#include <iostream>
#include <type_traits>
template<typename T>
struct TGetBaseTypeHelper
{
template<typename InternalType> static typename InternalType::DerivedType Test(const typename InternalType::DerivedType*);
template<typename InternalType> static void Test(...);
using Type = decltype(Test<T>(nullptr));
};
struct Base
{
using DerivedType = Base;
static void Print()
{
std::cout << "Base Logger" << std::endl;
}
};
struct Derived1 : Base
{
using BaseType = typename TGetBaseTypeHelper<Derived1>::Type;
using DerivedType = Derived1;
static void Print()
{
std::cout << "Derived1 Logger" << std::endl;
}
};
struct Derived2 : Derived1
{
using BaseType = typename TGetBaseTypeHelper<Derived2>::Type;
using DerivedType = Derived2;
static void Print()
{
std::cout << "Derived2 Logger" << std::endl;
}
};
int main()
{
Derived1::BaseType::Print();
Derived2::BaseType::Print();
}
Using a macro below to wrap those code make it simple:
#define DECLARE_BASE(T) \
public: \
using BaseType = typename TGetBaseTypeHelper<T>::Type; \
using DerivedType = T;
I got confused when first seeing these code. After I read #Xeo 's answer and #juanchopanza 's answer, I got the point.
Here's the keypoint why it works:
The decltype expression is part of the member declaration, which does
not have access to data members or member functions declared after
it.
For example:
In the declaration of class Derived1, when declaring Derived1::BaseType, Derived1::BaseType doesn't know the existence of Derived1::DerivedType. Because Derived1::BaseType is declared before Derived1::DerivedType. So the value of Derived1::BaseType is Base not Derived1.