I have an issue trying to use non-static data member init. in a complex template inheritance chain. I attach a small non-working example:
struct Builder {
template <typename T> T& get() {
return a;
};
float a = 5;
};
struct Base {
Builder a;
};
template <typename T> struct A: public Base {};
template <typename T> struct B: public A<T> {
float& b = (A<T>::a).get<float>(); // Do not work
Builder& builder = A<T>::a;
float& c = builder.get<float>(); // Work
};
struct C: public A<float> {
float& b = a.get<float>(); // Work
};
int main() {
return 0;
}
I'm most interested in class B. I have a compilation error using gcc 4.9.2:
error: expected primary-expression before ‘float’
float& b = (A<T>::a).get<float>(); // Do not work
I don't understand why it does not work as ti does compile if I use the trick two lines below (suffixed by the comment Work) which is basically the same thing.
It also works out of the box if my class is not a template. In this case, I can directly access the protected field by its name without using the syntaxe ParentClass<T>::field.
Do you have any ideas of what I'm doing wrong here?
Thanks a lot for your help!
Here get is a dependent name (it depends on T). You need to explicitly state it's the name of a template :
float& b = A<T>::a.template get<float>();
The second one works because you explicitly "collapse" A<T>::a into a Builder&, which does not depend on T anymore.
The third one works because you inherit from the fully specialized A<float>, which again does not depend on T.
Related
My question is how to make lifetime extension work with CRTP. For example, the following code is perfectly valid:
struct A {
const int& ref;
};
struct B {
const A& a;
};
int main() {
B b{{123}};
return b.a.ref;
}
Its CRTPed version is not:
template <class DerivedT>
class Gettable {
public:
int Get() const {
return static_cast<const DerivedT*>(this)->GetImpl();
}
};
class A : public Gettable<A> {
friend class Gettable<A>;
public:
A(int r) : ref{r}{}
private:
int GetImpl() const {
return ref;
}
const int& ref;
};
template <class T>
class B {
public:
B(const Gettable<T>& gettable) : get_{gettable}{}
int DifferentGet() const {
return get_.Get();
}
private:
const Gettable<T>& get_;
};
int main() {
B b{A{123}};
return b.DifferentGet();
}
The problem is that the original A and its Gettable<A> subobject only exist till the the of B constructor.
I have two questions:
1) Why? It is in no way different from the first case of structs, every lifetime is known at compile time, so I believe that compiler should be able to extend lifetime of all temporaries.
2) Is there any good way to overcome this issue?
1) Why?
Because there is a function involved - the constructor. The temporary is not bound directly to the member, but rather it is bound directly to the argument of the function - whose lifetime extends until the end of the function, which does not extend beyond the full expression that invoces the function.
It is in no way different from the first case of structs
It is different. There is no constructor involved in aggregate initialisation. In that case, the compiler knows the lifetime of the member, and it knows that the member is initialised with the temporary. The lifetime extension rule applies.
so I believe that compiler should be able to extend lifetime of all temporaries.
Consider following example:
struct foo {};
struct bar {
bar(const foo& farg);
const foo& fmem;
};
bar b({});
Should the lifetime of the temporary to extend for the lifetime of b? The standard says, that it doesn't. You appear to be arguing that it should.
Consider following possible implementations of the constructor:
bar::bar(const foo& farg) : fmem{farg} {} // 1
foo fanother;
bar::bar(const foo& farg) : fmem{fanother} {} // 2
If the implementation happens to be 1, then you guessed right, the life time extension is needed. If implementation is 2, then we are unnecessarily extending a temporary that is not referred to anymore.
The language designers chose to not extend such temporary, probably so that life times of temporaries don't get extended unnecessarily. As a consequence, implementation 1 is wrong, as well as your CRTP example.
Concisely: The compiler can only extend the lifetime of a temporary until the lifetime of the reference to which the temporary is bound directly. The compiler cannot know what will be done with the reference within the function. It cannot know that an argument has something to do with a member. Those are only known when the constructor is compiled - not when a call to the constructor is compiled.
2) Is there any good way to overcome this issue?
Use either int* or std::reference_wrapper<int> as the constructor argument. Former is more concise, but latter has convenient property of not having a null representation. These should make it harder to accidentally bind a dangling reference. Regardless, document carefully that the referred object must still be valid when Get is called.
I believe that the most general solution is something like this. This way it works even for multilevel inheritance.
#include <iostream>
#include <utility>
#include <type_traits>
struct NullType {};
// Helper class for casting
template <class Derived>
class DerivedCaster {
protected:
Derived* GetDerived() {
return static_cast<Derived*>(this);
}
const Derived* GetDerived() const {
return static_cast<const Derived*>(this);
}
};
// Matches the predicate against the types and remembers the first
// satisfying argument
template <template <class T> class Predicate, class... Args>
struct FindFirstMatching {
using Type = ... ; // default NullType
static const bool has_match = ... ;
};
// Structure which gets the deepest class from CRTP inheritance chain
// by looking at the instantiated parent class template
template<typename T>
struct GetDeepest
{
using Type = T;
};
template<template<class...> class DT, class... T>
struct GetDeepest<DT<T...>>
{
template <class CLS>
struct Predicate {
static const bool value = std::is_base_of<DT<T...>, CLS>::value;
};
static const bool HasCRTPDerived = FindFirstMatching<Predicate, T...>::has_match;
using DerivedT = typename FindFirstMatching<Predicate, T...>::Type;
using Type = std::conditional_t<HasCRTPDerived, typename GetDeepest<DerivedT>::Type, DT<T...>>;
};
// First abstract class
template <class DerivedT>
class Gettable : public DerivedCaster<DerivedT> {
public:
int Get() const {
return DerivedCaster<DerivedT>::GetDerived()->GetImpl();
}
};
// Second abstract class
template <class DerivedT>
class Incrementable : public DerivedCaster<DerivedT>,
public Gettable<Incrementable<DerivedT>> {
friend class Gettable<Incrementable<DerivedT>>;
public:
int Increment() const {
return ++(this->Get());
}
private:
int GetImpl() const {
return DerivedCaster<DerivedT>::GetDerived()->GetImpl() + 100;
}
};
// non-abstract class
class A : public Incrementable<A> {
friend class Incrementable<A>;
public:
A(int r) : ref_{r}{}
private:
int GetImpl() const {
return ref_;
}
int ref_;
};
// Helper to get the copy of the underlying non-abstract class
template <class T>
auto GetDeepestLevelCopy(const T& arg) {
return static_cast<const typename GetDeepest<T>::Type&>(arg);
}
// Some other class which wants a copy
template <class T>
class B {
public:
B(const Gettable<T>& gettable) : get_{GetDeepestLevelCopy(gettable)}{}
int DifferentGet() const {
return get_.Get();
}
private:
typename GetDeepest<Gettable<T>>::Type get_;
};
int main() {
static_assert(std::is_same_v<GetDeepest<Gettable<Incrementable<A>>>::Type, A>);
static_assert(std::is_same_v<decltype(GetDeepestLevelCopy(std::declval<Gettable<Incrementable<A>>>())), A>);
B b{A{123}};
std::cout << b.DifferentGet() << "\n";
// prints 223
return 0;
}
This looks monstrous, but I don't know whether there is a better solution.
I am having difficulty understanding the piece of code given below.
class Child1 : public Base1 {
public:
int Func1(char *Var);
}
class Cls_X: public std::enable_shared_from_this<Cls_X> {
public:
void Func2(char *Var_copy);
}
Func2 is called from Func1 as below
int Func1(char * Var){
...
make_shared<Cls_X>(ioc, ctx)->Func2(Varcopy_ptr);
...
}
Questions:
How class Cls_X: public std::enable_shared_from_this<Cls_X> works?
Tried googling but couldn't understand the documentation for this, Can someone explain in simple english?
Are Cls_X and Child1 both derived class of Base1 here?
NOTE:
The tag [boost] is added because the code example is taken from one of the boost libraries. Please check the example to see how shared_from_this is used in the program
Ps 1:- Change the suitable title if possible.
How class Cls_X: public std::enable_shared_from_this<Cls_X> works?
It can work iff the specialization of the template class (here std::enable_shared_from_this<Cls_X>) does not need to receive a type parameter (here Cls_X) that is a complete type.
template <typename T>
struct has_a_member { T mem; };
template <typename T>
struct has_a_pointer { T *ptr; };
struct A : has_a_member<A> // error at this point:
// A is incomplete at this point
// the definition of has_a_member<A> cannot be instantiated
{
};
struct B : has_a_pointer<B> // OK, B is incomplete
// still has_a_pointer<B> can be instantiated
{
};
And enable_shared_from_this is designed to work in that case, by expecting an incomplete type.
I got an example code as below:
#include <iostream>
template<class T1>
class B {
public:
B() : t1_(*this) {}
void Test() {
t1_.Test();
}
void Print() const {
std::cout << "test\n";
}
private:
T1 t1_;
};
template<template<class> class TB>
class A1 {
public:
explicit A1(const TB<A1<TB>> &b) : b_(b) {}
void Test() {
b_.Print();
}
private:
const TB<A1<TB>> &b_;
};
int main() {
B<A1<B>> bt;
bt.Test();
}
This is insight by this answer, this code make sure a class B has a member A1 and the A1 has a reference of B.
Although this code works, I really don't know how it works, especially the code const TB<A1<TB>> &b_;. Since the TB is a template template parameter, The TB<...> is a specialization of TB, which parameter is A1<TB>, right? Then what does the second TB in TB<A1<TB>> mean? If the second TB is a template, why there's no parameter?
As Matthieu Brucher mentioned, this code is indeed used to avoid an infinite recursion. Since I'm not fully understand how this code works, can any body explain how a compiler do to make this code work? Or, what should this code look like after it is being compiled?
The second TB doesn't have a parameter because of A1 declaration:
template<template<class> class TB>
class A1;
This says that A1 takes one template argument, and the parameter itself takes an unspecified template argument. A1 will do whatever it pleases with this template argument, but it must not be given when declaring A1, and this breaks the infinite recursion that would arise without this facility.
So for instance, you can write:
A1<TB> foo;
You can also write:
A1<std::vector> foo(std::vector<A1<std::vector>>()); // UB because of b storage, but it's the example
B expects a type, whereas A1 expects a template.
So you may have B<int> but not A1<int>.
Similar way, you may have A1<B> but not B<B>.
Back to
template<template <class > class TB> class A1;
TB is a template, not a type, but TB<int> is a type.
so for TB<A1<TB>>,
(inner) TB is a template.
A1<TB> is a type.
TB< T2 > is a type (with T2 = A1<TB>).
As inspired by Matthieu Brucher and Jarod42, I will try to use the view of a compiler to explain this, correct me if I'm wrong.
As Jarod42 mentioned:
(inner) TB is a template.
A1< TB > is a type.
TB< T2 > is a type (with T2 = A1)
and by the fact that template will instantiate when it is used, the line B<A1<B>> bt; is the place where the template fall into certain type.
So A1<B> is a type, let's make the real class named A1_IMPL, that is A1<B>--A1_IMPL, B<A1<B>> is a type, let make the class named B_IMPL, that is B<A1<B>>--B<A1_IMPL>--B_IMPL. So the B_IMPL looks like this:
class B_IMPL {
public:
B_IMPL() : t1_(*this) {}
void Test() {
t1_.Test();
}
void Print() const {
std::cout << "test\n";
}
private:
A1_IMPL t1_;
};
A1 will look like this:
class A1_IMPL {
public:
explicit A1_IMPL(const B<A1<B>> &b) : b_(b) {}
void Test() {
b_.Print();
}
private:
const B<A1<B>> &b_;
};
that's not finished, since A1<B>--A1_IMPL,B<A1<B>>--B<A1_IMPL>--B_IMPL, the final A1_IMPL will looks like this:
class A1_IMPL {
public:
explicit A1_IMPL(const B_IMPL &b) : b_(b) {}
void Test() {
b_.Print();
}
private:
const B_IMPL &b_;
};
there's no template any more.
I have the following class structure.
class Base {
protected:
template <typename Type>
Type convert(); // no implementation
public:
template <typename Type>
operator Type() {
Type t(convert<Type>());
// log conversion
return t;
}
}
};
class D1: public Base
{
protected:
template <type Type>
Type convert() {
Type t;
// Set t
return t;
}
};
template <typename Type>
class D2: public Base
{
public:
D2(Type v): value(v) {}
protected:
template <typename Type2>
Type2 convert() {
return value;
}
private:
Type value;
}
I am looking for a non-templated class that can be converted into a different type by a type conversion. I do not want to make Base a templated class, as that complicates how it is used.
I would like to force D2 to only allow Type2 and Type to be the same class. As written, if Type can be cast or converted to Type2, the code will work. I am being confused as to whether convert should be declared virtual (the answer appears to be no) and partial nested specializations.
I would like to provide a single specialization in D2 of
template <typename Type>
template <>
Type D2<Type>::convert<Type>() { ... }
but it is clear that this is not allowed.
I also tried
template <>
template <typename Type>
Type D2<Type>::convert<Type>() { ... }
which complained that "prototype for ‘Type D2::convert() const’ does not match any in class ‘D2’
I can't remove the template on convert because it is needed by D1.
Is there a way to get this to work?
At a high level, what I need is to be able to do the following:
Base *b = new D1(/*stuff*/);
int i = *b; // calls D1::convert<int> (a)
b = new D1(/*different stuff*/);
std::string s = *b; // calls D1::convert<std::string> (b)
b = new D2<int>(/* other stuff */);
int j = *b; // calls D2<int>::convert<int> (c)
b = new D2<std::string>(/*still other args*/);
s = *b; // calls D2<std::string>::convert<std::string> (d)
// This should fail as a compile time or link time error
b = new D2<int>(/*... */);
std::string s_fail = *b; // convertable to int, not string
// tries to call D2<int>::convert<std::string>, which is either
// not implemented or has an implementation that fails to compile,
// probably by casting an int to string (e)
The desired behavior is:
(a) Call a method in D1 that returns an int
(b) Call a method in D1 that returns a string
(c) Call a method in D2<int> that returns an int
(d) Call a method in D2<string> that returns a string
(e) Fail as early as possible, ideally at compile time or link time
Is that not possible in C++? I'm happy to rewrite everything except the public interface of Base, D1 not being templated and D2 being templated.
EDIT: Clarify the behavior that I want
I'm trying to let the return type of doSomeMethod() be the same as the operator() in the base class but if it's declared as protected the compiler rejects the code with error: no type named 'type' in 'std::result_of'. It works if it's public but i wonder if I could get it working for the protected case too since.
Here is simple code reproducing the error.
#include <type_traits>
class base
{
protected:
int operator()(){return 1;};
};
class child : private base
{
auto static doSomeMethod()
-> typename std::result_of<base()>::type
{
return 1;
}
};
EDIT:
Ok thanks Kerrek SB and Dietmar Kühlr for your solutions and explanations. After playing around with it I found this solution that is more readable and works (at least in my real case where child is template class and base one of its template parameters) more reliable.
But it seems that it goes a bit against your explanations. Or is it just the way std::result_of<> is broken in this case?
#include <type_traits>
class base
{
protected:
double operator()(){ return 1; };
int operator()(int i){ return i; };
};
class child : private base
{
public:
auto operator()()
-> decltype(base::operator()())
{
return base::operator()();
}
auto operator()(int i)
-> decltype(base::operator()(std::declval<int>()))
{
return base::operator()(i);
}
};
Thanks for your time.
If your code is literally this, then you can exploit the fact that the protected operator() from base is also available in child, and use a simple trait:
template <typename> struct memfn_result;
template <typename C, typename R, typename ...Args>
struct memfn_result<R (C::*)(Args...)>
{
using type = R;
};
class base
{
protected:
int operator()(){ return 1; };
};
class child : private base
{
memfn_result<decltype(&child::operator())>::type a; // "a" is an "int"
};
Since base::operator()() is protected and you are using it on an object of type base rather than an object of type child you clearly can't access the member! You need to access the function call operator using an object of type child. Sadly, child is incomplete in the context where you are trying to access it, i.e., you need to an indirection:
class child
: private base {
auto static doSomeMethod()
-> decltype((std::declval<base>().*(&child::operator()))()) {
return 1;
}
};