I think I need some tutoring on templates, especially in conjunction with inheritance. I am well aware those two concepts don't play very well together.
We've wanted to get ride of clang tidy warnings, but I have no clue how to achieve it.
The abstracted code is below, please see https://godbolt.org/z/sPfx7Yhad to compile it.
The setting is, we have some abstract base class (Animal), and a specialized type (Dog).
A converter functionality can only be defined on the base class.
There is a templated reader class, which is templated with the actual specialized typed (Reader<Dog>).
However, clang-tidy complains when analyzing reader.h, as converter::convert is not known.
It's only known in main.cpp, by including converter.h before reader.h.
I have tried to forward declare the function by using template:
namespace converter
{
template<typename T>
void convert(const std::string& input, T& animal);
}
Which leads to linker errors, because now the linker is looking for a void convert(const std::string&, Dog&) implemenation, rather than using the void convert(cons std::string&, Animal&) overload. (see https://godbolt.org/z/x4cPfh6P4)
What can I do? How could I change the design to avoid the clang-tidy warning?
In general, I cannot add the actual includes to converter.h in reader.h, as that part is generic and the user shall be able to use the reader with their own types, by providing a custom converter functionality.
What I cannot change are classes Dog and Animal. They are autogenerated classes / libraries which we are using.
For anyone who is interested, the real world example can be found here https://github.com/continental/ecal/blob/master/samples/cpp/measurement/measurement_read/src/measurement_read.cpp
#include <string>
#include <iostream>
// animal.h
// class hierarchy with abstract base class
class Animal
{
public:
std::string name;
virtual std::string what() = 0;
};
// dog.h
class Dog : public Animal
{
public:
std::string what() override {return "dog";}
};
// animal_converter.h
// converting function
// #include <animal.h>
namespace converter
{
void convert(const std::string& input, Animal& animal)
{
animal.name = input;
}
}
// reader.h
// Templated class for reader functionality
template <typename T>
class Reader
{
public:
T read()
{
T output;
converter::convert("Anton", output);
return output;
}
};
// main.cpp
// #include dog.h
// #include animal_converter.h
// #include reader.h
int main()
{
Reader<Dog> reader;
std::cout << reader.read().name << std::endl;
}
Related
I am learning c++ and confused about the ways to include another class in current class. For example, I am wondering whether class QuackBehavior equals to #include <QuackBehavior.h>. If they are equal, what are the differences between these two ways? The code is :
#include <string>
class QuackBehavior;
class Duck {
public:
Duck();
virtual ~Duck() {};
virtual void performQuack();
virtual std::string getDescription() = 0;
std::string getName() {return m_name;}
void setName(std::string name ) {m_name = name;}
void setQuackBehavior(QuackBehavior * behavior);
protected:
std::string m_name;
QuackBehavior * m_quackBehavior;
};
Thank you so much.
The two are not equal:
class QuackBehavior; is considered a forward-declaration, and simply informs the compiler that there is a class called QuackBehavior. This can only be used if you are using QuackBehavior as a pointer or reference:
class B;
struct C;
struct A
{
shared_ptr<B> getB() const { return b; }
const C& getC() const;
private:
shared_ptr<B> b;
};
Here the compiler doesn't need to know any implementation details of C and B, only that they exist. Notice that it's important to tell the compiler whether it's a class or struct also.
#include <QuackBehavior> is an include, and essentially copies+pastes the entire file into your file. This allows the compiler and linker to see everything about QuackBehavior. Doing this is slower, as you'll then include everything that QuackBehavior includes, and everything those files include. This can increase compile times dramatically.
Both are different, and both have their places:
Use forward-declaration when you don't need to know the implementation details of a class just yet, only that they exist (e.g. use in pointers and references)
Include the file if you are declaring an object, or you need to use functions or members of a class.
In QuackBehavior.h file, forwarding declaring QuackBehavior class will suffice.
#include <string>
class QuackBehavior; // tells the compiler that a class called QuackBehavior exists without any further elaborations
class Duck {
public:
Duck();
virtual ~Duck() {};
virtual void performQuack();
virtual std::string getDescription() = 0;
std::string getName() {return m_name;}
void setName(std::string name ) {m_name = name;}
void setQuackBehavior(QuackBehavior * behavior);
protected:
std::string m_name;
QuackBehavior * m_quackBehavior;
};
However in QuackBehavior.cpp file, you have to use #include"QuackBehavior.h" so that the compiler can find the implementation member functions
#include <QuackBehavior.h>
#include <string>
duck::duck()
{
}
I am jumping through hoops to reduce inheritance.
I read one similar question here. It shows how the issue can be resolved using a base class. I try to loose inheritance, so I am looking for something different - more along the lines of annotation.
I create and compile a template class with one specialisation (normal). The method that requires the template is in the header (Mixer.hpp). The method that does not require the template is in the cpp file (Mixer.cpp). When compiled into a static library, the cpp part only gets compiled as one specialisation (Mixer<normal>). The compiler does not know about (awsome) at that time. Importing the resulting static library into another project and attempting to create a different generic (awsome) class results in a linker error because obviously the library does not contain that method identifier (Mixer<awesome>::noTemplateInvolved). However the code for the normal implementation is as good as any so really the linker could just link to the existing source of the other template version (Mixer<?dontcare?>::noTemplateInvolved). All that the compiler has to do is to mark it appropriately for the linker.
Here is source code that results in a linker error:
//Target compiled to Provider.lib
//Mixer.hpp
#pragma once
#include <iostream>
using namespace std;
struct normal { static void log() { cout << "normal\n"; } };
template<typename output = normal>
class Mixer
{
public:
void callingTemplate();
void noTemplateInvolved();
};
template<typename output>
void Mixer<output>::callingTemplate() { output::log(); }
//Mixer.cpp
#include "Mixer.hpp"
void Mixer<>::noTemplateInvolved()
{
cout << "noTemplateInvolved\n";
}
//Target Compiled to User.exe
//This target imports Provider.lib
#include <Provider\Mixer.hpp>
#pragma comment(lib, "Provider.lib")
struct awsome { static void log() { cout << "awsome\n"; } };
int main()
{
Mixer<> n;
n.callingTemplate();
n.noTemplateInvolved();
Mixer<awsome> a;
a.callingTemplate();
a.noTemplateInvolved(); //linker error here
return 0;
}
The class Mixer<awsome> can link to the method callingTemplate because its definition is in the header and the compiler creates that function. At User.exe compile time the definition of noTemplateInvolved is hidden from the compiler. The compiler can not create that method and linking has to fail.
There are three solutions that I am aware of.
move the definition of noTemplateInvolved to the header.
include the cpp file
inherit from a baseclass
I am looking for another solution. The body of noTemplateInvolved really has nothing to do with the template. I would like to annotate the method in the header. I want the compiler to know it should always use the same base implementation regardless of the template.
Is that at all possible?
EDIT: Annotated that boring paragraph at the beginning a bit.
The answer turns out to be a base class as suggested in the comments. One of the reasons I wanted a base class is that I did not want to refactor. Refactoring using a base class is actually really simple.
Rename the original class to original_base.
Inherit from original_template inherits from original_base. Make sure to copy the contructor and pass through all the arguments to the base class.
The statement using original = original_template<your default case here> ensures that no other source code has to be modified just yet.
Applied to the example above I ended up doing something like this:
//Target compiled to Provider.lib
//Mixer.hpp
#pragma once
#include <iostream>
using namespace std;
struct normal { static void log() { cout << "normal\n"; } };
class Mixer_Base
{
private:
int mixcount;
public:
Mixer_Base(int count);
void noTemplateInvolved();
};
template<typename output = normal>
class Mixer_tempalte : public Mixer_Base
{
public:
Mixer_tempalte(int count) : Mixer_Base(count)
{}
void callingTemplate();
};
template<typename output>
void Mixer_tempalte<output>::callingTemplate()
{
output::log();
}
using Mixer = Mixer_tempalte<>;
//Mixer.cpp
#include "Mixer.hpp"
void Mixer_Base::noTemplateInvolved()
{
cout << "noTemplateInvolved\n";
}
Mixer_Base::Mixer_Base(int count) : mixcount(count)
{}
//Target Compiled to User.exe
//This target imports Provider.lib
#include <Provider\Mixer.hpp>
#pragma comment(lib, "Provider.lib")
struct awsome { static void log() { cout << "awsome\n"; } };
int main()
{
Mixer n(4);
n.callingTemplate();
n.noTemplateInvolved();
Mixer_tempalte<awsome> a(3);
a.callingTemplate();
a.noTemplateInvolved();
return 0;
}
In a way an annotation feels just like the base class feels. Everything in the base class is now annotated the way I wanted it to be, though this does not reduce inheritance.
I have seen a few articles on generic programming and how you should never use virtual functions and templates together. I understand this idiom, as templates are decided at compilation, where virtual functions are not chosen until run-time (over simplification).
However, I have a bit of code that uses OO style and Generic style together and it seems to work the way I want.
My Question:
Is the following design bad practice. Mixing Polymorphism and Generic Code?
Is there any pit falls with my code below. (I know I should not inherit data members, but I have :-/).
#ifndef BaseTemplate_H
#define BaseTemplate_H
#include <vector>
template< class T >
class BaseTemplate {
public:
typedef std::vector<T*> pVT;
BaseTemplate(){}
virtual ~BaseTemplate(){};
virtual void Process()=0;
const pVT& getContainer(){ return m_pContainer; }
protected:
pVT m_pContainer;
private:
BaseTemplate( const BaseTemplate& cpy );
BaseTemplate& operator=( const BaseTemplate& rhs);
};
#endif
I inherit from the base class first by telling the base template what type I would like when inheriting.
This will allow me two inherit for multiple types, which I want to keep separate in my design.
#ifndef DerClassA_H
#define DerClassA_H
#include <iostream>
#include "BaseTemplate.h"
class DerClassA: public BaseTemplate<int> {
public:
DerClassA(){}
virtual ~DerClassA(){}
virtual void Process(){
std::cout << "HELLO I AM: DerClassA" << std::endl;
}//This will push_back objects to m_pContainer
private:
DerClassA( const DerClassA& cpy );
DerClassA& operator=( const DerClassA& rhs);
};
#endif
#ifndef DerClassB_H
#define DerClassB_H
#include <iostream>
#include "DerClassA.h"
class DerClassB: public DerClassA {
public:
DerClassB(){}
virtual ~DerClassB(){}
virtual void Process(){
std::cout << "HELLO I AM: DerClassB" << std::endl;
}//This will push_back objects to m_pContainer
private:
DerClassB( const DerClassB& cpy );
DerClassB& operator=( const DerClassB& rhs);
};
#endif
#include "DerClassA.h"
#include "DerClassB.h"
int main()
{
BaseTemplate<int> *pClassA = new DerClassA();
pClassA->Process();
DerClassA *pClassB = new DerClassB();
pClassB->Process();
delete pClassA;
delete pClassB;
return 0;
}
Is the following design bad practice. Mixing Polymorphism and Generic Code?
No, that's sometimes the right thing to do.
Is there any pit falls with my code below.
The container with raw pointers std::vector<T*> pVT; looks a bit fishy.
The base class destructor should probably be pure virtual.
I would use the C++11 syntax for making the class non-copyable.
You only need to make the base class non-copyable.
I don't see the need for dynamic allocation in your main function.
For the rest I don't see any immediate errors.
It's not possible to say whether or not your design is good without knowing what you are trying to do.
I want a static constant, LIST_DELIMITER, defined in my class below. However, I can't figure out how to declare it with templates.
// MyClass.h
#pragma once
#include <boost/algorithm/string.hpp>
#include <vector>
class MyClass
{
public:
MyClass();
virtual ~MyClass();
template<class T>
void GetAsVectorOfValues(std::vector<T> values)
{
boost::split(values, value_, boost::is_any_of(LIST_DELIMITER));
}
private:
std::string value_;
static const std::string LIST_DELIMITER;
};
// MyClass.cpp
std::string MyClass::LIST_DELIMITER = ",";
I know there are similar question on stackoverflow but I can't seem to find what I'm looking for. One thing that is different in my case is that my whole class is not templated, just the single method.
You have to use the exact same declaration, including qualifiers:
const std::string MyClass::LIST_DELIMITER = ",";
^^^^^
There's no template involved in this static class member definition.
Is it possible to use member function pointers with template meta-programming? Such as:
class Connection{
public:
string getName() const;
string getAlias() const;
//more stuff
};
typedef string (Connection::*Con_Func)() const;
template<Con_Func _Name>
class Foo{
Connection m_Connect;
public:
Foo(){
cout << (m_Connect.*_Name)();
}
};
typedef Foo<&Connection::getName> NamedFoo;
typedef Foo<&Connection::getAlias> AliasFoo;
Granted, this is rather contrived but is it possible? (yes, there are probably much better ways but humor me.)
Check out this discussion on the subject of pointers-to-nonstatic-members as template parameters. It looks like there are issues with the VC++ implementation.
If you are asking, can pointers to members be used as template parameters, then yes they can. There are a number of errors in your code though. This is, I think, what you might mean:
// Necessary includes
#include <string>
#include <iostream>
#include <ostream>
class Connection{
public:
// Use std:: for standard string class
std::string getName() const;
std::string getAlias() const;
//more stuff
};
typedef std::string (Connection::*Con_Func)() const;
template<Con_Func _Name>
class Foo{
Connection m_Connect;
public:
// Constructors don't have return values
Foo(){
// Correct syntax for function call through pointer to member
std::cout << (m_Connect.*_Name)();
}
};
typedef Foo<&Connection::getName> NamedFoo;
typedef Foo<&Connection::getAlias> AliasFoo;