Simple nested class - c++

I have a beginner question regarding nested classes in c++. There are a lot of information on the internet about this but i still can't get it to work properly without compile errors. I simply want to return the inner class B from a function inside class A.
template<class T>
class A
{
public:
A();
class B
{
public:
B(){};
};
B getB();
};
template<class T>
A<T>::A(){}
template<class T>
B A<T>::getB{return B();}
When i do this i get the error "B does not name a type". I believe the solution is to use typedef class A<T>::B b_class;, but i still end up with the same error.
Thank you!

You need to change a few things: add parens to the function definition, qualify the outer B with the enclosing class (A<T>::) alongside with typename (required because the type depends on the type of A) and change the return to actual object creation.
Here, listed in fixed source:
template<class T>
typename A<T>::B A<T>::getB() {return B();}
//^----------------------------------------------typename
// ^---------------------------------------qualification
// ^---------------------parens
// ^---------c-tor call

template<class T>
B A<T>::getB{return B b;}
There are three issues here:
B at the start of the declaration does not name the type A<T>::B. You need to be explicit about it, either by using typename A<T>::B or with a trailing return type so that B refers to the correct name.
You don't have () after getB
Your syntax for creating a temporary B is incorrect, it should be B() or B{}
Here is a fixed version:
template<class T>
auto A<T>::getB() -> B { return B{}; }

A is the name of a template, so A<T> is the name of the (instantiated) class.
Thus, the full name of the nested class is A<T>::B, but since B depends on the template parameter T and is a type, you must specify template A<T>::B.
The tricky bits is that inside the declaration of A you can refer to B simply by using the B name. And you can refer to the instantiation of A<T> by using A, using what is called the injected class name. So inside the class declaration, A can refer both to the template and the class instantiation.
Answering your question:
template<class T>
typename A<T>::B A<T>::getB()
{
B b;
return b;
}
Note that the return type is outside the declaration of the function, so you need to use the fully qualified name.

Related

Variadic template only compiles when forward declared

I have a variadic template that inherits from all template arguments:
template <typename... Ts>
struct derived : Ts...
{
};
I would also like to have a facility for expressing the type of "existing derived with added template arguments". My attempt at this is:
// Do not ODR-use (goes in namespace impl or similar)!
template<class ... NewInputs, class ... ExistingInputs>
auto addedHelper(const derived<ExistingInputs...>&)
-> derived<ExistingInputs..., NewInputs...>;
template<class ExistingInput, class ... NewInputs>
using Added = decltype(addedHelper<NewInputs...>(std::declval<ExistingInput>()));
As a simple example, Added<derived<A, B>, C> should be derived<A, B, C>. I use the helper function for template argument deduction of the first parameter pack.
My problem: For some reason, I can use this successfully with incomplete types if derived has been forward declared, but not if it was defined.
Why does this code not compile:
#include <utility>
template <typename... Ts>
struct derived : Ts...
{};
template<class ... NewInputs, class ... ExistingInputs>
auto addedHelper(const derived<ExistingInputs...>&)
-> derived<ExistingInputs..., NewInputs...>;
template<class ExistingInput, class ... NewInputs>
using Added = decltype(addedHelper<NewInputs...>(std::declval<ExistingInput>()));
struct A;
struct B;
struct C;
// Goal: This forward declaration should work (with incomplete A, B, C).
auto test(derived<A, B> in) -> Added<decltype(in), C>;
struct A {};
struct B {};
struct C {};
void foo()
{
auto abc = test({});
static_assert(std::is_same_v<decltype(abc), derived<A, B, C>>, "Pass");
}
Whereas this code does compile:
#include <utility>
template <typename... Ts>
struct derived;
template<class ... NewInputs, class ... ExistingInputs>
auto addedHelper(const derived<ExistingInputs...>&)
-> derived<ExistingInputs..., NewInputs...>;
template<class ExistingInput, class ... NewInputs>
using Added = decltype(addedHelper<NewInputs...>(std::declval<ExistingInput>()));
struct A;
struct B;
struct C;
// Goal: This forward declaration should work (with incomplete A, B, C).
auto test(derived<A, B> in) -> Added<decltype(in), C>;
template <typename... Ts>
struct derived : Ts...
{};
struct A {};
struct B {};
struct C {};
void foo()
{
auto abc = test({});
static_assert(std::is_same_v<decltype(abc), derived<A, B, C>>, "Pass");
}
For convenience, here are both cases at once (comment in/out #define FORWARD_DECLARED): https://godbolt.org/z/7gM52j
I do not understand how code could possibly become illegal by replacing a forward declaration by the respective definition (which would otherwise just come later).
Evg's observation hits the nail on the head: the problem here is ADL. It's actually the same problem I ran into with this question.
The issue is this: we have an unqualified call here:
template<class ExistingInput, class ... NewInputs>
using Added = decltype(addedHelper<NewInputs...>(std::declval<ExistingInput>()));
// ^^^^^^^^^^^
We know it's a function template because we find it in using regular lookup, so we don't have to deal with the whole "is < an operator or a template introducer" question. However, because it's an unqualified call, we also must perform argument-dependent lookup.
ADL needs to look into the associated namespaces of all the arguments, which seems fine - we don't need complete types for that. But ADL also needs to look for potential friend functions and function templates defined within the classes. After all, this needs to work:
struct X {
friend void foo(X) { }
};
foo(X{}); // must work, call the hidden friend defined within X
As a result, in our call in question:
auto test(derived<A, B> in) -> Added<decltype(in), C>;
We have to instantiate derived<A, B>... but that type inherits from two incomplete classes, which we can't do. That's where the problem is, that's where we fail.
This is why the forward declaration version works. template <typename... T> struct derived; is incomplete, so just trying to look inside of it for friend functions trivially finds nothing - we don't need to instantiate anything else.
Likewise, a version where derived was complete but didn't actually derive from anything would also work.
Thankfully, this is fixable in this context with what Evg suggested. Make a qualified call:
template<class ExistingInput, class ... NewInputs>
using Added = decltype(::addedHelper<NewInputs...>(std::declval<ExistingInput>()));
This avoids ADL, which you didn't even want. Best case, you're avoiding doing something that has no benefit to you. Bad case, your code doesn't compile. Evil case, for some inputs you accidentally call a different function entirely.
Or just use Boost.Mp11's mp_push_back

accessing definitions from sub class in templated class

I have trouble to build a class which itself contains a subclass which self derives from class which needs template parameters from the top class. Sound horrible and it is indeed deep inside some MTP construction. But have a look on a simple example which I could shrink from the real code.
I leave the names as is in my original source. They are not important here.
template <typename ... T>
class ConstructAll: public T...
{
public:
using ConstructorParms = int;
using BASES_T = ConstructAll<T...>;
ConstructAll(int){}
};
template <typename T>
class WithTemplate
{
};
class WithoutTemplate
{
};
template <typename X>
class CircuitFromNetlist
{
private:
class SerialReader: public ConstructAll<
WithTemplate<X> // use this-> don't compile
//WithoutTemplate // but this works
>
{
public:
SerialReader( typename BASES_T::ConstructorParms p): BASES_T( p ) {}
};
public:
CircuitFromNetlist()
{
SerialReader ser{1};
}
};
int main()
{
CircuitFromNetlist<int> c;
}
If I use WithTemplate<X>it did not compile and runs into:
main.cpp:31:40: error: 'BASES_T' has not been declared
SerialReader( typename BASES_T::ConstructorParms p): BASES_T( p ) {}
^~~~~~~
main.cpp: In constructor 'CircuitFromNetlist::SerialReader::SerialReader(int)':
main.cpp:31:70: error: class 'CircuitFromNetlist::SerialReader' does not have any field named 'BASES_T'
SerialReader( typename BASES_T::ConstructorParms p): BASES_T( p ) {}
If I flip the code to use non templated class it seems to work.
Some idea to get the thing working?
What you're seeing here is actually correct behavior according to the C++11 standard:
In the definition of a class or class template, if a base class depends on a template-parameter, the base class scope 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. -- [temp.dep] (emphasis mine)
When you inherit from ConstructAll<WithoutTemplate>, the base class does not depend on the template parameter X, but obviously inheriting from ConstructAll<WithTemplate<X>> the base class does depend on this template parameter.
You will have to explicitly refer to the type as typename ConstructAll<WithTemplate<X>>::BASES_T.

How to refer to a type defined in a derived class passed as a template argument?

Consider the following example:
template <typename T>
class A {
private:
typedef typename T::C C;
};
template <typename T>
class B : public A<B<T>> {
public:
typedef T C;
};
int main() {
B<int> b;
}
Compiling it with GCC gives the following error:
test.cc:5:23: error: no type named 'C' in 'B<int>'
typedef typename T::C C;
~~~~~~~~~~~~^
test.cc:9:18: note: in instantiation of template class 'A<B<int> >' requested here
class B : public A<B<T>> {
^
test.cc:15:10: note: in instantiation of template class 'B<int>' requested here
B<int> b;
^
Why does compiler give an error if B::C is defined and how to fix it?
At this point,
class B : public A<B<T>> {
… class B is incomplete. Class A can't look inside it.
The C type definition inside B is accessible from that point inside B, and on. It's also available inside function bodies in B because you can regard a function definition inside the class definition as a shorthand for placing it after the class. But an incomplete class contains nothing as viewed from outside: all that outside code can do is form pointers and references and use the class as template argument.
template< class C >
using Ungood = typename C::Number;
struct S
{
void foo() { Number x; (void) x; } // OK
Ungood<S> uhuh; //! Nyet.
using Number = double;
};
auto main() -> int {}
You can fix your code by changing the design. The most obvious is to pass the type as a separate template argument. But depending on what you're trying to achieve it may be that the inheritance you currently have, isn't really needed or even useful.
You can't because you're in a chicken-egg paradox. The definition of the base requires knowledge of the definition of the derived, which needs the definition of the base to complete. You simply have to come up with an alternative. One example would be to use an external metafunction to communicate the needed type to whoever needs it. Hopefully that's not in any part of the definition of the base's members or you're probably screwed.
Other alternative is to pass T as a second parameter.
You can't do that because of this:
A class is considered defined after the closing brace of its class-specifier has been seen [...]
And a few exceptions, none of which are valid in your case.
In other terms, you must consider your derived class as not fully defined when you try to use it in your base class to access the type C.
Anyway, you can exploit the fact that your derived class is a template class and do this:
template <typename T>
class A;
template <template<typename> class D, typename T>
class A<D<T>> {
private:
using C = T;
};
Aa you can see, I've not given a definition for the primary template class, thus only the specialization for template classes can be used.
Not sure this is the OP's real case, but it's the case in the example in the question.

C++: Scope of templated base class?

This code does not compile:
template <typename T>
struct B {
typedef T type;
};
struct D0 : public B<int> {
void h(type) { }
};
template <typename T>
struct D : public B<T> {
void f(typename B<T>::type) { }
void g(type) { }
};
http://ideone.com/pVh94t
Specifically, although D0::h(type) and D::f(typename B<T>::type) compile, D::g(type) does not. Why is type not visible in D?
Answer can be found in two places. First C++11 draft standard N3337:
§14.6.2/3
In the definition of a class template or a member of a class template,
if a base class of the class template depends on a template-parameter,
the base class scope 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. [ Example:
typedef double A;
template<class T> class B {
typedef int A;
};
template<class T> struct X : B<T> {
A a; // a has type double
};
The type name A in the definition of X<T> binds to the typedef
name defined in the global namespace scope, not to the typedef name
defined in the base class B<T>. — end example ]
(Bold emphasis mine)
Second, the parashift FAQ provides a human-readable explanation in Why am I getting errors when my template-derived-class uses a nested type it inherits from its template-base-class?:
Perhaps surprisingly, the following code is not valid C++, even though
some compilers accept it:
template<typename T>
class B {
public:
class Xyz { /*...*/ }; // Type nested in class B<T>
typedef int Pqr; // Type nested in class B<T>
};
template<typename T>
class D : public B<T> {
public:
void g()
{
Xyz x; // Bad (even though some compilers erroneously (temporarily?) accept it)
Pqr y; // Bad (even though some compilers erroneously (temporarily?) accept it)
}
};
This might hurt your head; better if you sit down.
Within D<T>::g(), name Xyz and Pqr do not depend on template parameter
T, so they are known as a nondependent names. On the other hand, B<T>
is dependent on template parameter T so B<T> is called a dependent
name.
Here’s the rule: the compiler does not look in dependent base classes
(like B<T>) when looking up nondependent names (like Xyz or Pqr). As a
result, the compiler does not know they even exist let alone are
types.
At this point, programmers sometimes prefix them with B<T>::, such as:
template<typename T>
class D : public B<T> {
public:
void g()
{
B<T>::Xyz x; // Bad (even though some compilers erroneously (temporarily?) accept it)
B<T>::Pqr y; // Bad (even though some compilers erroneously (temporarily?) accept it)
}
};
Unfortunately this doesn’t work either because those names (are you
ready? are you sitting down?) are not necessarily types. “Huh?!?” you
say. “Not types?!?” you exclaim. “That’s crazy; any fool can SEE they
are types; just look!!!” you protest. Sorry, the fact is that they
might not be types. The reason is that there can be a specialization
of B<T>, say B<Foo>, where B<Foo>::Xyz is a data member, for example.
Because of this potential specialization, the compiler cannot assume
that B<T>::Xyz is a type until it knows T. The solution is to give the
compiler a hint via the typename keyword:
template<typename T>
class D : public B<T> {
public:
void g()
{
typename B<T>::Xyz x; // Good
typename B<T>::Pqr y; // Good
}
};
Apparently, this is due to the compiler's order of semantic compilation phases. It happens that, to the compiler's view, the symbol type is not present in any scope, because it hasn't (yet) instantiated templates, and thus, it hasn't instantiated D itself.
The only workaround is to force the compiler to resolve the symbol in a later phase of semantic compilation, such as with...
void f(typename B<T>::type) {}
Or, if the derived class is not a template, but the base class is, the compiler is forced to resolve/instantiate/whatever the base class first, thus avoiding any possible errors inside the derived class.
But this is not the case if both base and derived are templates, because the compiler will look-up a symbol for the derived in all already instantiated scopes (such as the global scope) before instantiating the derived template class, and if it fails, well you already know what happens with int main(){printf("%d\n", argc);}, no?

Base class template member function shadowed in Derived class, albeit different parameter list

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;