C++ Nested Template Classes - c++

How can I return a "B" type using a method of an "A" class? For example:
template <typename T> class A{
//something
template <typename V> class B{
//something
};
B& foo(){
B<T> y; //the variable must have the same type T of the father class (for my exercise)
//something
return y;
}
};
main:
A <int> o;
o.foo();
Once I try to compile it, it gives me these errors:
"invalid use of template-name 'A< T >::B' without an argument list" at "B& foo()..."
and
"'class A' has no member named 'foo'"
I have written the function "foo" after closing the class B, so it might be right...

There are three problems with your code:
The public access specifier is missing. foo() won't be accessible outside class A otherwise.
You need to add the template arguments to the return type as well, i.e. declare the member function as B<T> foo(). Even better, let the compiler deduce the return type (works with C++14 and beyond), so just write auto foo()
You are returning a reference to a local variable, which leads to undefined behavior. Just return the local variable as value, due to copy elision you won't need to worry about performance issues.
With that in mind, your code should work.

Related

Template type deduction according to constructor argument

I have a class template whose constructor accepts a callable whose type is a template parameter. I would like to have that type deduced so I don't have to specify it whenever instantiating the class.
Unfortunately, the type deduction doesn't work in the example below. Is there a way to get it to work?
template<typename F>
class C {
public:
C(F&& f) : m_f{f} {}
private:
F m_f;
};
class D {
public:
static int s() { return 0; }
private:
C<decltype(&s)> c {&s}; // OK
C<> c2 {&s}; // error, not enough template parameters
};
https://wandbox.org/permlink/8cphYR7lCvBA8ro4
Note this is similar to Can template parameter deduction be used in class data members? but here I'm asking about getting something similar to work, not about standard compliance.
One more note is that while re-specifiying the type of the template parameter in the example above is just a non-DRY inconvenience (which one of the answers below suggests solving with a macro), I'm not sure how it would be possible to have an instance of C with F being a non-global lambda function type (e.g. one that's defined on the spot), in case that instance is a data member. A technique which would allow that would be very powerful and useful, IMHO.
If your main goal is to avoid typing &s twice, the pragmatic solution is to define a macro:
#define CC(name,value) decltype(C{value}) name{value}
class D {
public:
static int s() { return 0; }
private:
CC(c,&s);
// lambda still not possible:
// CC(c2,[](){return 42;});
};
You could do something like this:
decltype(C{&s}) c{&s};
But I'm not aware of a way to avoid duplicating the &s.

C++ Template: What happens if we put wrong thing in our template class

C++ templates allow we put whatever in our objects with template arguments. However, if our template arguments use functions/variables which belong to certain types, how do we check?
template<typename BarType>rguments
class Foo {
public:
Foo() { bar = new BarType() }
private:
BarType * bar;
}
Foo<Bar> …
BarType could be anything derived from a Bar superclass.
What happens if we invoke some functions which only belong to Bar in our Foo class? What happens if we pass non-BarType? Do we have anyway to check?
You will get a compile-time error if your templated code makes reference to members that the actual parameter doesn't provide when you try to instantiate the template. So don't worry, you won't be able to break anything.
Think of templates as a code-generation mechanism. Whether the generated code actually makes sense can sometimes only be determined when you actually try it.
Given the class template TempFoo below, you see that it calls the example function of the templated T type in its constructor. The first two types work because they both define example; the third doesn't.
template<typename T>
class TempFoo
{
void TempFoo() {
T obj;
obj.example();
}
};
class First {
void example() {}
};
class Second {
void example() {}
};
class Third {
};
int main()
{
TempFoo<First> f; // works
TempFoo<Second> s; // works
TempFoo<Third> t; // doesn't
}
Whatever you're giving in the tempalte parameter list is simple a place place holder. Compiler will repalce with appropriate types according to the type of object which is used to instantiate the template class. A compile-time error will be appear if the object doesn't satify the operations done in the functions. Also it's a good practice to use 'T' as place holder.
An easy way to ensure that the template parameter derives from the base class:
template<typename BarType>
class Foo
{
// ...
~Foo() { Bar* p = (BarType*)0; }
};
The compiler will type-check the assignment, generating an error if Bar isn't an unambiguous supertype of BarType, and then optimize away the unused local variable.

Keyword "typename" in Templates

Following is the code and quote is from the C++ Templates by Addison Wesley:
template <typename T>
class MyClass {
typename T::SubType * ptr;
…
};
Without typename, SubType would be considered a static member. Thus, it would be a concrete variable or object. As a result, the expression T::SubType *ptr would be a multiplication of the static SubType member of class T with ptr.
Now when I compile that code without the keyword 'typename', the error I get is this: type ‘T’ is not derived from type ‘MyClass<T>’.
Is the compiler recognizing 'T'?
If not, then shouldn't it be a undefined reference error?
If yes, then why is this an error?
Alright here is the complete code:
#include <iostream>
#include <vector>
template <typename T> class MyClass
{
T::SubType * ptr;
};
int main ()
{
return 0;
}
The error I am getting is this:
~/Desktop/notes **g++ templates/programs/trial.cpp**
templates/programs/trial.cpp:6: error: type ‘T’ is not derived from type ‘MyClass<T>’
templates/programs/trial.cpp:6: error: expected ‘;’ before ‘*’ token
Here's another way to get the same error from g++:
class Foo { static const int x = 0;};
template <typename T> class MyClass
{
Foo::x * ptr;
};
and another:
class Foo { static const int x = 0;};
class MyClass
{
Foo::x * ptr;
};
But you get a different error for this:
// class Foo { static const int x = 0;};
template <typename T> class MyClass
{
Foo::x * ptr;
};
So:
Because T is a dependent type, g++ assumes that T::SubType is an object that will be defined by the time second-phase lookup occurs. That's as expected, and is the usual reason that typename is required here.
Even if T::SubType exists and is an object, the code is still bad, just like Foo::x *ptr is bad when Foo::x exists and is an object. I still don't understand what the error message is about - how would it help for Foo to be derived from MyClass? But the error message is nothing to do with templates.
"Undefined reference" is a linker error. Since this code fails to even compile, you shouldn't expect to see "undefined reference to T" anywhere.
I don't so far see how Foo even could be derived from MyClass. I tried the following to see whether it would give a clue to the meaning of the original message, but it fails because MyClass is an incomplete type, which doesn't tell me anything about what would happen if Foo were derived from MyClass:
class MyClass
{
class Foo: public MyClass { static const int x = 0;};
Foo::x * ptr;
};
Comeau gives far more sensible error messages for all these cases - nothing about derived types, just says that T::SubType isn't a type. So explaining g++'s error message is going to take either knowledge or good guesses about g++ internals, and exactly where in the process of trying to parse your class template it finally gives up.
Without typename, SubType would be considered a static member. Thus, it would be a concrete variable or object. As a result, the expression T::SubType *ptr would be a multiplication of the static SubType member of class T with ptr.
This description is incorrect when applied to the example you give. In class bodies there can be no expressions, and no constructs are parsed as a multiplication. However, in the C++03 syntax, there is a construct that looks as follows
struct Base { int a; };
struct Derived : Base {
Base::a; // access-declaration
};
This construct was deprecated in C++03 but still supported, and means the same as the following
struct Base { int a; };
struct Derived : Base {
using Base::a; // using-declaration
};
Because you didn't tell the compiler that T::SubType is a type and hence tell the compiler that it should parse it as the type of a pointer declaration, the compiler assumed that T::SubType is the name in an access-declaration. Hence it expected a semicolon directly after it, and hence it expected that T is a base class of MyClass<T> (or that MyClass<T> is a derived class of T). The error message actually has it backwards:
if (! UNIQUELY_DERIVED_FROM_P (IDENTIFIER_TYPE_VALUE (cname),
ctype))
{
cp_error ("type `%T' is not derived from type `%T'",
IDENTIFIER_TYPE_VALUE (cname), ctype);
...
}
While the macro says
/* Nonzero iff TYPE is uniquely derived from PARENT. Under MI, PARENT can
be an ambiguous base class of TYPE, and this macro will be false. */
#define UNIQUELY_DERIVED_FROM_P(PARENT, TYPE) ...
Because T::SubType is a dependent name, you need to tell the compiler that SubType is a type (not a static data member) by typing typename keyword.
Read about dependent name here:
Name binding and dependent names (C++ only)
Dependent Names (scroll down and read this section - better if you read the complete article)
EDIT:
As for your question (which you repeated in the comment):
I think what you've posted is not the complete code. So I cannot specifically comment on that. Also, sometimes compilers aren't smart enough to point out the error in template code accurately. So I suggested you to read about dependent name and when & why typename is required. Hopefully, after that you will not have any question!

"Using" directive fails within template

I understand that the member names of a base-class template are hidden within the scope of a derived class, and therefore must be accessed using this->foo or Base<T>::foo. However, I recall that C++ also allows you to use the using keyword, which can come in handy in a derived-class function which frequently accesses a base-class variable. So, in order to avoid cluttering up the function with this-> everywhere, I'd like to use the using keyword.
I know I've done this before, but for whatever reason I can't get it to work now. I'm probably just doing something stupid, but the following code won't compile:
template <class T>
struct Base
{
int x;
};
template <class T>
struct Derived : public Base<T>
{
void dosomething()
{
using Base<T>::x; // gives compiler error
x = 0;
}
};
int main()
{
Derived<int> d;
}
The error, (with GCC 4.3) is: error: ‘Base<T>’ is not a namespace
Why doesn't this work?
It doesn't work because C++ language has no such feature and never had. A using-declaration for a class member must be a member declaration. This means that you can only use in class scope, but never in local scope. This all has absolutely nothing to do with templates.
In other words, you can place your using-declaration into class scope
struct Derived : public Base<T> {
...
using Base<T>::x;
...
};
but you can't have it inside a function.
Using-declarations for namespace members can be placed in local scope, but using-declarations for class members cannot be. This is why the error message complains about Base<T> not being a namespace.
Outside class scope (if you are in a block etc), you can only name namespace members in a using declaration.
If you don't want to place that using declaration into the scope of Derived (which IMO is the favorable solution), your other option is to use a reference
int &x = this->x;
x = 0;
It should be noted that this is semantically different, because it
Forces a definition to exist for Base<T>::x, which might not be the case for static const data members
Forces Base<T>::x to be of type int& or be convertible to type int&.
Otherwise, if you want to avoid using this-> all again, I don't see other options.
template <class T>
struct Base
{
int x;
};
template <class T>
struct Derived : public Base<T>
{
using Base<T>::x;
void dosomething()
{
x = 0;
}
};
int main()
{
Derived<int> d;
}
As others said, it is working only class scope.

Declaring an instance of an explicit specializtion of a template within a regular class

I can't get this to compile at all. I may not be possible but I don't know why it should not be.
class A {
template <typename T>
class B {
int test() { return 0; }
};
//template <> class B<int>; <-with this, namepace error
B<int> myB_;
};
template <> class A::B<int> {
int test() {
return 1;
}
};
As it appears the compiler complains "The explicit specialization "class A::B" must be declared before it is used."
If I try to provide the froward declaration in the commented line, the compiler complains
"The explicit specialization "B" must be declared in the namespace containing the template."
We use 2 different compilers here. This error is from IBM's "xl" compiler on AIX but I get similar errors with different verbage when compiling on our Sun systems.
It seems like a catch-22.
Obviously, this is a highly contrived, simplistic example but, it represents the problem.
I want to define a template class within a class because the template class is only relevent to the containing class. There should be no access to the template from outside the class.
Am I missing something?
You are correct. This is not possible to do (as far as I know). Your member declaration causes an implicit instantiation before the explicit specialization was declared. But how would you want to declare it? You cannot do that in class scope. Others have felt that this is an ugly restriction.
You could work around this by making the class member a pointer. This would not need to implicitly instantiate the class at that point, but rather at the point where you create the object in the end. I realize that this is an ugly work around. So better find other ways to do this.
For instance partial specializations are allowed in class scope. So you could add a dummy template parameter, then you can specialize this in the class before the member declaration. Likewise, i find this ugly, but it would not disturb things that much, I feel.
You could work around the issue by using an unnamed namespace for privacy:
namespace {
template <typename T>
class B {
int test() { return 0; }
};
template <> class B<int> {
int test() {
return 1;
}
};
}
class A {
B<int> myB_;
};
This will compile, but if A needs to be visible outside this compilation unit, you'll need more elaborate machinery (e.g., interface and factory or Pimpl).
B is not a template class and you are trying to specialize it. That is the cause for the error. You can check these two errors C2913 and C3413.
Is this what you are looking for?
class A
{
template<class T>
class B
{
inline int test()
{
return 0;
}
};
A::B<int> myB_;
};