Derived Template-Class Access to Base-Class Member-Data

Derived template-class access to base-class member-data

You can use this-> to make clear that you are referring to a member of the class:

void Bar<T>::BarFunc () {
std::cout << this->_foo_arg << std::endl;
}

Alternatively you can also use "using" in the method:

void Bar<T>::BarFunc () {
using Bar<T>::_foo_arg; // Might not work in g++, IIRC
std::cout << _foo_arg << std::endl;
}

This makes it clear to the compiler that the member name depends on the template parameters so that it searches for the definition of that name in the right places. For more information also see this entry in the C++ Faq Lite.

Accessing base member functions in class derived from template class [duplicate]

When a class template derives from a base class template, the base members are not visible in the derived class template definition. (This makes sense; until you specialize, there is no class, and so there are no members. Explicit specializations can always change the meaning of any given template class.)

In other words, the base template member names are dependent names and not looked up in the first phase of template definition lookup.

There are three ways to get around this. Let's make it concrete with a quick example:

template <typename T> struct Foo
{
int data;
using type = const T &;
void gobble() const;
template <int N> void befuddle();
};

template <typename T> struct X : Foo<T> { /* ... */ };

Now in the context of the derived class template definition, you can...

  1. Qualify the name:

    Foo<T>::data = 10;
    typename Foo<T>::type x;
    Foo<T>::gobble();
    Foo<T>::template befuddle<10>();
  2. Use this:

    this->data = 10;
    this->gobble();
    this->template befuddle<10>();

    (This doesn't work for type names names.)

  3. Use a using declaration:

    using Foo<T>::data;
    using Foo<T>::gobble;
    using type = typename Foo<T>::type;

    data = 10;
    gobble();

    (This doesn't work for template names.)


Update: After your edit, the question is entirely different. Templates don't play a role at all here, since the problem doesn't contain templates, only classes. What's happening is the simple fact that member functions in a derived class hide member functions of the same name in base classes, so the presence of SpecificDerived2::memberFunc hides the base member function. The simple solution is to unhide base members of the same name with a using declaration:

class SpecificDerived2 : public TemplateBase2<float>
{
public:
using TemplateBase2<float>::memberFunc;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

float memberFunc()
{
return 3.14;
}
};

Accessing variables from base template class in derived class constructor in C++

arr is a dependent name now. It depends on T. What if there is some T for which Base<T> is specialized to not have an arr? Specifically, from [temp.dep]:

In the definition of a class or class template, the scope of a dependent base class (14.6.2.1) is not examined
during unqualified name lookup
either at the point of definition of the class template or member or during
an instantiation of the class template or member.

Base<T> is a dependent base class - it depends on the template parameter T, so its scope is not examined during unqualified name lookup. The way around this is to use qualified name lookup. That is, either the class name:

parr = &Base<T>::arr[0];

or just with this:

parr = &this->arr[0];

C++ templates: Calling member function of derived template class from base class

As C++ is a strongly typed language, you can't call them directly this way, since the compiler would not be able to figure out what the return value of the function is.

What you need to do is, map it all to a common interface. The question you should ask is: what are the information i realy need from the CelField? Maybe all you need is the string-representation of the value, then you could do something like this:

class CellBase
{
virtual std::string getData()=0;
};

template<typename T>
class CellField : public CellBase
{
std::string getData(){//some implementation}
};

Another option is the use of boost::any, which is able to contain any type you like. This is especially useful if you don't need to actually interfere with the returned value other than passing it to some other function taking "an arbitrary parameter". However in order to really use the value, you still have to cast it to a specific type using boost::any_cast<T>() and therefore need to know which type you expect and do a proper error-handling if the type is wrong.

Why can a C++ template class access a private member of its base class?

The posted code does not call Derived<int>::get_a() so that template member function does not get instantiated (and there is no "access" of the private parent member to speak of).

Adding the following get_a() call causes the same error as in the non-template case.

{
Derived<int> d;
d.get_a(); // error: 'A* Base::m_pA' is private within this context
}

[ EDIT ]   The implicit instantiation of template member functions (only) when used is ruled in the C++ standard under temp.inst/4:

Unless a member of a templated class is a declared specialization, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist or if the existence of the definition of the member affects the semantics of the program;

An explicit definition of the template specialization (though not just a declaration) will cause full instantiation of all members, resulting in the same error.

extern template class Derived<int>; // explicit declaration - ok

template class Derived<int>; // explicit definition - error: 'A* Base::m_pA' is private within this context

[ EDIT #2 ]   The argument was made in the comments (thanks @Jarod42) that the given code falls into the "ill-formed, no diagnostic required" category, meaning the compiler is allowed (though not required) to reject it on grounds that no possible (complete) instantiation of the class template Derived<T> can exist because of the private member access in get_a() even if the member function is never used.

This interpretation is based on the following section of temp.res.general/6.1:

The program is ill-formed, no diagnostic required, if:

  • no valid specialization can be generated for a template or a substatement of a constexpr if statement within a template and the template is not instantiated, or [...]
  • If "valid specialization can be generated" is taken to mean a complete explicit specialization of the entire template class, then the given code snippet is indeed "ill-formed NDR".

  • If, however, "valid specialization" is understood to cover implicit specializations of the template class with (only) the required members as defined in temp.inst/4 quoted earlier, then the given code snippet does not fall under "ill-formed NDR" because get_a() is never instantiated (per temp.inst/11: "an implementation shall not implicitly instantiate a function template, a variable template, a member template, a non-virtual member function, a member class or static data member of a templated class, or a substatement of a constexpr if statement, unless such instantiation is required").

The linked demo shows that gcc takes the latter interpretation, while clang the former.

In either case, the answer stands that if the template is not rejected upfront as "ill-formed NDR" because of the no-valid-specializations-can-exist clause, then it will compile and work fine as long as get_a() does not get instantiated, either implicitly by direct reference, or by an explicit specialization of the template class.

Why doesn't a derived template class have access to a base template class' identifiers?

That's two-phase lookup for you.

Base<T>::NO_ZEROFILL (all caps identifiers are boo, except for macros, BTW) is an identifier that depends on T.

Since, when the compiler first parses the template, there's no actual type substituted for T yet, the compiler doesn't "know" what Base<T> is. So it cannot know any identifiers you assume to be defined in it (there might be a specialization for some Ts that the compiler only sees later) and you cannot omit the base class qualification from identifiers defined in the base class.

That's why you have to write Base<T>::NO_ZEROFILL (or this->NO_ZEROFILL). That tells the compiler that NO_ZEROFILL is something in the base class, which depends on T, and that it can only verify it later, when the template is instantiated. It will therefore accept it without trying to verify the code.

That code can only be verified later, when the template is instantiated by supplying an actual parameter for T.

Visibility of members of base template class not directly inherited

You are using A<X> where a base class is expected.

[namespace.udecl]

3 In a using-declaration used as a member-declaration, each
using-declarator's nested-name-specifier shall name a base class of
the class being defined.

Since this appears where a class type is expected, it is known and assumed to be a type. And it is a type that is dependent on the template arguments, so it's not looked up immediately.

[temp.res]

9 When looking for the declaration of a name used in a template
definition, the usual lookup rules ([basic.lookup.unqual],
[basic.lookup.argdep]) are used for non-dependent names. The lookup of
names dependent on the template parameters is postponed until the
actual template argument is known ([temp.dep]).

So it's allowed on account of the compiler not being able to know any better. It will check the using declaration when the class is instantiated. Indeed, one can put any dependent type there:

template<bool> struct D{};

template <bool X>
struct C : public B<X> {
using D<X>::x;
C() { x = 1; }
};

This will not be checked until the value of X is known. Because B<X> can bring with it all sorts of surprises if it's specialized. One could for instance do this:

template<>
struct D<true> { char x; };

template<>
struct B<true> : D<true> {};

Making the above declaration be correct.



Related Topics



Leave a reply



Submit