Nested class as a template parameter of parent class in C++ - c++

I want to implement an algorithm as a class deriving from a pure virtual class representing the kind of problem the particular algorithm solves.
The general interface would look like this:
template<typename A, typename B>
class ISolutionToProblem
{
public:
virtual void Init(const A & input, const B & param) = 0;
virtual const B & ComputeSolution() = 0;
virtual ~ISolutionToProblem() {}
};
And the implementation would be for example:
template<typename T>
class MyAlgorithm:
public ISolutionToProblem<typename MyAlgorithm<T>::WorkData, T>
{
public:
struct WorkData { /* Stuff using T... */ };
virtual void Init(const WorkData & input, const T & param);
virtual const T & ComputeSolution();
virtual ~MyAlgorithm();
};
(to be more specific, the problem is actually path finding, but I don't think it is relevant)
My problem is the inheritance part: I am using a nested struct as a template parameter, and no matter how nicely I try to talk to the compiler, it keeps refusing to compile my code.
I could go lazy and just put the inner structure outside of the class, but if possible I'd prefer it to stay neatly placed in the class.
So is what I am trying to do actually possible (in C++98)?
If so, how should I write it ? (bonus points if you get me to understand why the syntax doesn't accept the form above)
Otherwise, what am I doing wrong? (is my design flawed to begin with?)
Here is how the compiler error looks like.
g++ (4.8):
error: no type named ‘WorkData’ in ‘class MyAlgorithm<int>’
clang (3.1):
error: no type named 'WorkData' in 'MyAlgorithm<T>'
VS2012:
error C2146: syntax error : missing ',' before identifier 'WorkData'
see reference to class template instantiation 'MyAlgorithm<T>' being compiled
error C2065: 'WorkData' : undeclared identifier
error C2955: 'ISolutionToProblem' :
use of class template requires template argument list
see declaration of 'ISolutionToProblem'

I think your problem is the the compiler doesn't know what the inner class looks like until it has defined the outer class and the outer class is defined with the inner class as a template parameter. I'm not 100% sure this can't be made to work. The CRTP is an example similar to this that is known to work.
Templates can be used to create inheritance hierarchies, but should not be use the in the definition of a hierarchy. If that sounds confusing, it's because it is. Inheritance and template classes don't mix well. Notice that even though CRTP uses inheritance and templates it does not use virtual functions.

Related

Can I fill a template parameter with a nested class in this class?

For example, I got a class looks like this:
template <typename T>
class Test {
public:
T* t;
...
};
then (how) can I extends the class which is similar like this?
class TestImplement : Test<TestImplement::TestInner> // the TestInner class is defind in the class {
class TestInner {};
...
};
Since the TestInner is defined after where the template needs, this code is illegal, and a forward declaration is useless too.
Well, you simply can't do that, and you've already pointed out why that is.
Thinking more about logic than about syntax, since the base class definition may very well differ depending on what its template argument is, and since the base class definition may very well affect the way TestInner works, you are attempting to create a circular dependency which is just not possible in our physical reality.
You could experiment with using TestImplement as the template argument (CRTP!) and then look up typename TemplateArgument::TestInner from within the base, but even if this works I doubt its clarity.
I'd use a non-nested class instead.

Invalid use of auto when declaring a variable C++, C++11

Whenever I try to compile my code I get an invalid use of auto. Coming from a Java background, I am not sure if I quite understand C++ templates. It seems like the compiler can infer the type. I am limited to C++11.
The error occurs in the GeneralRenderer.
Animal classes
class Animal {};
class Dog : public Animal {};
class Cat : public Animal {};
enum AnimalType {
Dog,
Cat
};
Render Classes
template<class T>
class AnimalRenderer {
virtual void draw(T entity) = 0;
};
class DogRenderer : public AnimalRenderer<Dog> {};
class CatRenderer : public AnimalRenderer<Cat> {};
Logic
class GeneralRenderer {
public:
void draw(
std::map<AnimalType, std::vector<Animal>> animalMap) {
for (auto entry: animalMap) {
AnimalRenderer<auto> renderer; // <--- Causes the error
switch (entry.first) {
case Dog:
renderer = DogRenderer();
break;
case Cat:
renderer = CatRenderer();
break;
}
for (auto animal: entry.second) {
renderer.draw(entry);
}
}
};
};
Informally speaking, auto can be used to declare and initialise a type at the same time. Then the compiler can infer the type from the value used to initialise the variable.
But that's not the case here; a statement like
auto n;
will fail similarly.
Note that auto merely stands in for a type that is known at compile time. It's there to make code more readable although its use is occasionally obligatory such as when working with lambda functions. It is not a variant-type construct cf. std::variant say of C++17.
Finally note that a std::map is a very different beast to a java.util.Map. There's no type erasure in C++ so a std::map<A, B> is a fundamentally different type to a std::map<C, D> if A is a different type to C and / or B differs from D. Furthermore, C++ allows you to store value types in maps.
As the other users already say, auto can‘t work without a righthand variable.
I think you should remove the template annotation from AnimalRenderer, then you can use the classes normally.
To get the result you want you effectively need to move the second for-loop inside the cases, where the deduction can be resolved for each case.
You don't want code duplication, so ideally you want a template function you can call to do the second loop. On the latest c++ standards you might also be able to declare a template lambda function.
That said, architecturally, I would suggest adding an interface base class for AnimalRenderer, and then you can declare a simple pointer to that base class, especially as you have already declared draw as virtual.

C++ Calling function that has template which has inheritance

So I have a class that defines a TileGrid:
template<typename T>
class TileGrid { ... };
I fill in the template with a class called ImageTile
class ImageTile { ... };
I have a child class of ImageTile that I have defined that looks like this:
class FFTWImageTile : public ImageTile { ... };
In a separate file I define the following function:
void writeDataToFile(TileGrid<ImageStitching::ImageTile> * grid, std::string fileName);
(note: both ImageTile and FFTWImageTile are in the ImageStitching namespace)
Now all of the above compiles just fine, but when I try to use it I get an error.
Here is an example test case that is using it:
namespace is = ImageStitching;
TileGrid<is::FFTWImageTile> * grid = new TileGrid<is::FFTWImageTile> ( ... );
writeTranslationsToFile(grid, "output.txt");
When compiling the test case I get the following error:
error: cannot convert ‘TileGrid<ImageStitching::FFTWImageTile>*’ to ‘TileGrid<ImageStitching::ImageTile>*’ for argument ‘1’ to ‘void writeTranslationsToFile(TileGrid<ImageStitching::ImageTile>*, std::string)’
Anyway I can make this happen in C++?? I've looked all over and cant seem to find some help with making a function that has a parameter featuring a template that has child/parent relationships.
Edit:
Everyone's answers have been exceptional and each solve the issue presented. I think decided to move to C++11 and use an assert for this particular case. In the future I think I will add a template to the function and ensure to get the data that way. Thank you all for the help! I have marked what I think is the best answer although each have been acceptable.
You are getting the error because despite that FFTWImageTile is derived from ImageTile, TileGrid<FFTWImageTile> and TileGrid<ImageTile> are absolutely unrelated classes.
How to fix this depends on the implementation of the classes which you haven't shown. Perhaps you can make writeDataToFile() templated:
template<typename T>
void writeDataToFile(TileGrid<T> * grid, std::string fileName);
Options that might work for you.
Make writeDataToFile a function template.
template <typename T>
void writeDataToFile(TileGrid<T> * grid, std::string fileName);
In the implementation of this function, use another function template to write individual elements of the tile.
template <typename T>
void writeTileElement(T const& tileElement, std::ostream& out);
You can create overloaded versions of writeTileElement to take care of special handling of different types of objects.
Use a TileGrid of ImageTile* instead of ImageFile.
void writeDataToFile(TileGrid<ImageStitching::ImageTile*> * grid, std::string fileName);
You generate two different classes with
TileGrid<ImageStitching::ImageTile>
and
TileGrid<is::FFTWImageTile>
They have no relation other than being generated from the same template. You would want to derive from the class TileGrid<ImageStitching::ImageTile> to have an actual subclass for type purposes.
You could templatize the function writeDataToFile, but to enforce type restrictions on template arguments, you should use something like...
static_assert(is_base_of<T, ImageStitching::ImageTile>>(), "T is not a base of ImageTile");
static_assert
is_base_of

generics JAVA in c++? how to do <X extends T>?

class T : public std::string {
public:
T(char* s) : std::string(s){};
};
class X : public T {
public:
X(char* s) : T(s) {};
~X() {};
};
template <typename T> T doIt(const T arg);
int main(int argc, const char* argv[]) {
X s("initial string");
T s2 = doIt(s);
printf("out %s", s2.c_str());
}
T doIt(T arg) {
arg.append(" appended");
return arg;
};
What is the problem with my code.. the output is bellow...
1>Linking...
1>TemplateStuding1.obj : error LNK2001: unresolved external symbol "class X __cdecl doIt(class X)" (??$doIt#VXClass####YA?AVXClass##V0##Z)
1>D:\Programming\cpp\cpp-how-to-program\CppHowToProgram\Release\Test.exe : fatal error LNK1120: 1 unresolved externals
Once you get past the problem with the missing template <class T> on your definition of doIt (that others have already mentioned), you'll still want an answer to your question:
Is it possible to make a template argument <X extends T> like in Java?
The answer to this question is no. C++ does not have constrained generics like Java does. There was a proposal on the table to add something like this (but much different) called "concepts" in C++0x, but it was just too complicated and has been dropped.
In brief, there are 3 ways to do generics that are relevant:
Duck typing (what Ruby has). This is what C++ has now. If an class responds to all of the same methods as class T then it will fit the bill, even if it's not inherited from class T. In addition, if you try to pass class Z which is missing some methods that class T has, you'll never find out if the template doesn't try to call them. If the template does try to call them, then a compiler error will appear at the place where the template tries to call the missing method. (You'll find out which template instantiation caused the problem from a stack trace that the compiler will spit out explaining what templates it was trying to instantiate when it encountered the error.) You do get a compiler error in C++ (unlike Ruby, where it's a runtime error), but it's a complicated error message.
Structural typing (what Scala has). Concepts in C++ were intended to move in this direction. If an class responds to all of the same methods as class T then it will fit the bill, even if it's not inherited from class T. If that class doesn't respond to all of the same methods, it's an error, even if the template function doesn't try to call the missing method. Template errors are reported at the site of instantiation. (C++'s version of this would be more complicated because you can do declare operators on an object as free functions, but the basic idea is the same.)
Constrained generics (for lack of a better term -- what Java has). Any class passed to the template must be a subtype of class T. Having the same methods won't cut it unless there's real inheritance. Members of the C++ standardization commitee don't like this -- they prefer #2 over #1 (if they can work out all of the technical issues) and #1 over #3 -- so it will probably never appear in C++.
Would someone else please post an answer untangling this guy's use of class T in this example. He's using it in 2 different ways, and I'm not sure whether his use of T in template <class T> (as opposed to some other letter) was meant to specify a constraint on the types that could be passed. This may be a significant confusion. On the other hand, using T in both places may just be a careless error. I really can't tell.
Here is the problem:
template <typename T> T doIt(const T arg); // <---- declared but not defined
int main(int argc, const char* argv[]) {
//...
T s2 = doIt(s); // <------ it is calling above method (which is visible)
}
T doIt(T arg) { // <------ T is `class T`, not `template`, so different method
arg.append(" appended");
return arg;
};
Here when you define T doIt(T) after main(), you expect that you are defining the body of the above template method. Which is not true. You don't get compiler error because, coincidentally you have class T; which will pass the definition of T doIt(T).
If you intend to use template doIt then your definition should be as,
template<typename T>
T doIt(T arg) { // <------ T is now `template`; thus same method
arg.append(" appended");
return arg;
};
[Also note that, you get linker error because you din't have any real definition of template doIt and whatever definition you had below main() was not visible.]
Your compiler is complaining that you declared but never implemented doIt. All it is right now is a signature, and yet you're calling it like it's actually defined.
On a side note, what on earth does this error have to do with java? Or generics even?

Ambiguous call if class inherits from 2 templated parent classes. Why?

I have a templated class that performs an action on the class that is given as template argument. For some of my classes I want to 'group' the functionality in one class, to make it easier for the caller. In fact the code looks something like this (names were changed):
template<typename T>
class DoSomeProcessing
{
public:
process(T &t);
};
class ProcessingFrontEnd : public DoSomeProcessing<CustomerOrder>, public DoSomeProcessing<ProductionOrder>
{
};
The problem is that when I call ProcessingFrontEnd::process with a CustomerOrder as argument, that the compiler complains about it.
I tried to reproduce the problem in a smaller test application. This is the code:
#include <vector>
class X : public std::vector<char>
, public std::vector<void *>
{
};
int main(void)
{
X x;
x.push_back('c');
return 0;
}
And indeed, if this is compiled, Microsoft's VS2010 compiler gives this error:
test.cpp
test.cpp(11) : error C2385: ambiguous access of 'push_back'
could be the 'push_back' in base 'std::vector<char,std::allocator<char> >'
or could be the 'push_back' in base 'std::vector<void *,std::allocator<void *> >'
test.cpp(11) : error C3861: 'push_back': identifier not found
I tested this test application with different types (char+void*, double+void*) and different arguments in the call ('c', 3.14), but the error message is always the same.
I tested this with VS2005 and VS2010 but I always get the same error.
Why can't the compiler determine the correct function to call? What makes this confusing for the compiler? Or is it just a bug in the Microsoft compiler?
EDIT:
If I explicitly add 2 push_back methods to my class, like this:
class X : public std::vector<char>
, public std::vector<void *>
{
public:
void push_back(char c) {}
void push_back(void *p) {}
};
The compiler doesn't complain anymore. So with these methods he can clearly distinguish between a character and a void-pointer. Why can't he do this if the two push_back methods are inherited from the parent?
This is by design. The compiler is not trying to resolve overloaded
functions because these are not overloaded
functions. The standard is really clear on that
(see 10.2.2). If the same name is found in two
different bases, it's an ambiguity, even if they
could be resolved correctly with the call (i.e. in
your case). Same-named functions in different classes will typically have quite different purposes and hence the selection between them should not be made on the basis of
their arguments. There are many good reasons not to
allow that, but here's one.
Imagine your class C derives from A and B and
these two base classes come from two different
libraries. If the author of B adds a new function
to the class, it may break the user's code by
redirecting a call from A::foo() to B::foo() if
the latter is a better match.
If you want the two functions to be treated in the same way that they would
be if part of a single class, then the best way to do it is with using
declarations in the derived class. Just add
using std::vector<char>::push_back;
using std::vector<void *>::push_back;
to the declaration of class X.
I believe you are running afoul of the C++ overloading rules which prohibit overloading across classes. You'd get the same results if your template classes were two separate classes, each with its own process(CustomerOrder) and process(ProductionOrder) member.
The workaround is explicit using statements inside your derived class, pulling in each overload from each of the template base classes.
How is the compiler supposed to know which process you want to call? There's two options. Do you want both, one, or the other?
You need to override process in the derived class.