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;
Related
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;
}
A professor at uni wanted us to implement a stack using an std::vector, and to write an "unstacking" iterator for it (that is, an iterator which when iterated over pops the top of the stack).
Everything could have been fine until he also decided he wanted all of it to be generic, using templates and all. That's when hell began.
So the first thing I did was writing template<typename T> class VectorStack:
//file VectorStack.hpp
template <typename T>
class VectorStack
{
public:
VectorStack();
virtual size_t size();
virtual bool empty();
virtual void push(T obj);
virtual T pop();
private:
vector<T> _data;
};
Implementation may not be relevant here so I'll skip it. Don't hesitate to ask if you need it.
Then I had to write template<typename T> class VectorStackIterator...
In order for that iterator to unstack an instance of VectorStack, it must contain at least a pointer to that instance. So VectorStackIterator needs to know about VectorStack, which leads us to a first forward declaration.
But also, VectorStack has begin() and end() methods which are supposed to return a VectorStackIterator. So VectorStack also needs to know about VectorStackIterator, which leads us to a second forward declaration.
So I wrote my iterator in a separate file:
//file VectorStackIterator.hpp
template<typename T>
class VectorStack; //Forward declaration of the VectorStack
template<typename T>
class VectorStackIterator : public iterator<random_access_iterator_tag, VectorStack<T>>
{
public:
VectorStackIterator(size_t n, VectorStack<T>* instance);
T operator--();
bool operator==(VectorStackIterator other);
bool operator!=(VectorStackIterator other);
private:
VectorStackIterator();
T& operator=() {};
size_t _n;
VectorStack<T>* _instance;
};
...and updated my VectorStack to look like this:
//file VectorStack.hpp
template<typename T>
class VectorStackIterator; //Forward declaration of the iterator
template <typename T>
class VectorStack
{
public:
//...
VectorStackIterator<T> top();
VectorStackIterator<T> bottom();
//...
};
Again, implementation of the iterator may not be relevant.
At this point, I already had the compiler screaming because I was using incomplete types everywhere. So I tried out something else: I put the declarations of both the VectorStack and the VectorStackIterator at the beginning of the same file, and only then, I put the definitions of all of the methods. Here is what it looks like:
//file VectorStack.hpp
#ifndef VECTOR_STACK_HPP
#define VECTOR_STACK_HPP
#include <vector>
using std::vector;
#include <iterator>
using std::iterator;
#include <exception>
using std::out_of_range;
template <typename T>
class VectorStack;
//still had to forward-declare this because VectorStackIterator uses it in its own declaration.
//Class declaration (VectorStackIterator)
template<typename T>
class VectorStackIterator : public iterator<random_access_iterator_tag, VectorStack<T>>
{
public:
VectorStackIterator(size_t n, VectorStack<T>* instance);
T operator--();
bool operator==(VectorStackIterator other);
bool operator!=(VectorStackIterator other);
private:
VectorStackIterator();
T& operator=() {};
size_t _n;
VectorStack<T>* _instance;
};
//Class declaration (VectorStack)
template <typename T>
class VectorStack
{
public:
VectorStack();
virtual size_t size();
virtual bool empty();
virtual void push(T obj);
virtual T pop();
VectorStackIterator<T> top();
VectorStackIterator<T> bottom();
private:
vector<T> _data;
};
All of this is followed by the definition of every method declared above. I don't think that's where the error lies in, but please ask if you want me to provide it.
This is the closest attempt to a solution that I've come up with, but the compiler still complains about Incomplete types not allowed here when I declare a VectorStack<int> object in the main function:
#include "VectorStack.hpp"
int main(int argc, char** argv)
{
VectorStack<int> v; //Incomplete types not allowed here
v.push(0); //Incomplete types not allowed here
v.push(1); //Incomplete types not allowed here
v.push(2); //Incomplete types not allowed here
for (auto it = v.top(); it != v.bottom();) //Incomplete types not allowed here (x2)
{
cout << it-- << endl;
}
return 0;
}
If I try to forward-declare the iterator instead of the vector stack, then the vector stack is no longer incomplete, but the iterator is, and I get errors on the heading line of the for loop.
It looks like the compiler won't ever go beyond the forward declaration, to the actual definitions that make everything complete.
I'm running out of options, do you have any ideas?
It's a bit hard to follow your post. But in general, there are some things to keep in mind:
Class members stored by value require complete types to be available at the time that the containing class is declared, because the compiler needs to know how much memory the object should take.
Pointer and reference members do not need to be complete when declaring the containing class, because the size is always just the size of a pointer.
Complete types are always required as soon as you start to use the object in question, because the compiler needs to know what member variables and functions that type should contain.
If you ever get into a situation where you can't resolve "incomplete type" errors, double check your design to make sure that it makes sense; you don't want (for example) two types to circularly contain each other (by value, again references and pointers are fine).
That said, I think the standard way to handle this is:
class ClassB;
class ClassA {
ClassB* or ClassB&
}
class ClassB {
ClassA
}
ClassA::implementations // These two can happen in any order, since both ClassA and ClassB are complete at this point
ClassB::implementations
Since both of your classes are templated, the implementations need to be put in header files, so you may need to be careful with the way you structure your files to enforce the order in which these pieces will happen.
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 apologize if this has been asked, I'm not sure how one best words it and couldn't really find it.
I essentially have a class that I want to maintain a map of itself, and that list should have the only instantiations of the object.
using std::unordered_map;
class MyClass
{
~MyClass() {};
MyClass() {}; // these actually contain code which operate on the classes data
static unordered_map<Uint32, MyClass> list;
public:
static const MyClass& GetObject(Uint32 key) {return list[key];};
};
When i compile my code it basically gives me a bunch of errors from the STL saying it's calling deleted functions and such, which makes sense because unordered_map probably uses the constructor and destructor, so I declared unordered_map a friend
friend class unordered_map<Uint32, MyClass>;
However there doesn't seem to be any fewer errors, which I speculate is due to classes used by unordered_map like pair, and hash. So my question is if there is an alternative to this. Should I just declare more things friends that appear to be giving errors in from the compiler, or is there another method?
So. You're in the mood to do something annoying. So let's do it. As AlexD says, what you're missing is a public destructor. The unordered_map needs access to this (possibly through some implementation defined inner class).
So let's do that, and let's do what you should have done in the first place, which is to make a much smaller and simpler test case:
#include <unordered_map>
class MyClass {
public:
~MyClass() {}
private:
MyClass() {}
};
int main() {
std::unordered_map<int, MyClass> x;
x.at(3);
//x[3];
}
Now that compiles fine.
Now, note that I have commented out x[3]. We can't use that. That's because if 3 doesn't exist in the map, we'd call the default constructor of MyClass, which is private. And because the compiler doesn't know at compile time if that's true, it will need to ensure that it could call the constructor.
From the comments, there's a concern that you couldn't insert any objects into this map. Well, let's add a static factory method and get rid of that concern:
#include <unordered_map>
using std::unordered_map;
class MyClass {
public:
static MyClass factory() { return MyClass(); }
~MyClass() {}
private:
MyClass() {}
int x;
};
int main() {
std::unordered_map<int, MyClass> x;
x.insert(std::make_pair(3, MyClass::factory()));
x.emplace(4, MyClass::factory());
}
UPDATE: T.C. kindly pointed out a couple things I'd overlooked, so this answer's done a complete about-face....
#include <iostream>
#include <unordered_map>
#include <map>
#include <cinttypes>
class MyClass
{
typedef std::unordered_map<uint32_t, MyClass> Instances;
friend Instances;
friend std::pair<uint32_t, MyClass>;
friend std::pair<const uint32_t, MyClass>;
public:
static const MyClass& getObject(uint32_t key) { return instances_[key] = 2 * key; }
~MyClass() {}
int n() const { return n_; }
private:
MyClass() : n_(-1) { }
MyClass& operator=(int n) { n_ = n; return *this; }
int n_;
static Instances instances_;
};
MyClass::Instances MyClass::instances_;
int main() {
const MyClass& m20 = MyClass::getObject(20);
const MyClass& m21 = MyClass::getObject(21);
std::cout << m20.n() << ' ' << m21.n() << '\n';
}
Above code at ideone.com.
As per comments, the list of necessary friendship isn't documented by the Standard, so could break with new compiler versions or when porting to another compiler.
Alterantively, you can store (smart) pointers in the unordered_map.
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.