Template class that has all virtual functions inline - c++

I'm using class templates which contain virtual functions in my current project, and I stumbled upon a problem I can't overcome on my own.
Class templates cannot have their member function bodies split from class
definition in .hpp file because of linker errors. I don't want to
instantiate my templates for each new type I'm abut to use, so all
that's left is to leave them inlined. This is absolutely
fine as they are 1-2 lines long most of the time, so I'm not going
to experience any code bloat.
On the other hand, gcc creates vtable for a polymorphic class in
.cpp file that has definition of the first non-inline function that
is declared in the class definition. Since I have all member
functions inline, I'm getting undefined reference to vtable, or no
RTTI symbol found for my class in GDB.
Please consider the following code:
template <typename T>
struct Test
{
virtual void testMe() const = 0;
virtual ~Test() = default;
};
template <typename T>
struct test : public Test<T>
{
virtual void testMe() const
{
std::cout << typeid(T).name() << std::endl;
}
virtual ~test() = default;
};
int main()
{
test<int> t;
Test<int>& T = t;
T.testMe();
return 0;
}
In this particular example I'm getting:
can't find linker symbol for virtual table for `test<int>' value
when debugging with GDB.
How do I force my compiler to put vtable in a specific cpp file when all class functions are inline?
EDIT:
Since the example provided above didn't illustrate the problem, here's my original code.
The class that's causing the problem:
#ifndef CONVERTIBLETO_H
#define CONVERTIBLETO_H
#include "convertibleTo_converters.h"
#include <functional>
template <
typename IT,
template <typename InterfaceType, typename ErasedType>
class Converter = convertibleTo_detail::default_converter
>
class convertibleTo
{
public:
typedef convertibleTo<IT, Converter> this_type;
typedef IT InterfaceType;
struct is_type_eraser_tag {};
private:
class holder_interface
{
public:
virtual InterfaceType get() const = 0;
virtual void set(const InterfaceType&) = 0;
virtual holder_interface* clone() const = 0;
virtual ~holder_interface() {}
};
template <typename ErasedType>
class holder : public holder_interface
{
public:
virtual InterfaceType get() const
{
return (Converter<InterfaceType, ErasedType>::convert(this->data));
}
virtual void set(const InterfaceType& value)
{
this->data = (Converter<InterfaceType, ErasedType>::convert(value));
}
virtual holder_interface* clone() const
{
return new holder(*this);
}
holder() = delete;
holder(const holder& other):
data(other.data)
{ }
holder(ErasedType& d):
data(d)
{ }
virtual ~holder() = default;
private:
ErasedType& data;
};
public:
inline InterfaceType get() const
{
if (this->held)
return this->held->get();
else
return InterfaceType();
}
inline void set(const InterfaceType& value)
{
if (this->held)
this->held->set(value);
}
inline bool empty() const
{
return ! this->held;
}
convertibleTo<InterfaceType, Converter>& operator= (const convertibleTo<InterfaceType, Converter>& other)
{
if(this->held)
delete this->held;
this->held = other.held->clone();
return *this;
}
convertibleTo():
held(nullptr)
{ }
template <typename T>
explicit convertibleTo(T& data):
held(new holder<T>(data))
{
}
convertibleTo( convertibleTo& other ):
convertibleTo( const_cast<const convertibleTo&>(other))
{
}
convertibleTo( const convertibleTo& other ):
held(nullptr)
{
if(other.held)
this->held = other.held->clone();
}
~convertibleTo()
{
if (this->held)
delete this->held;
}
private:
holder_interface * held;
};
#endif
Required helper classes:
#ifndef CONVERTIBLETO_CONVERTERS_H
#define CONVERTIBLETO_CONVERTERS_H
#include <string>
#include <sstream>
namespace convertibleTo_detail
{
template <typename InterfaceType, typename ErasedType>
struct default_converter
{
static inline InterfaceType convert(const ErasedType& input)
{
return input;
}
static inline ErasedType convert(const InterfaceType& input)
{
return input;
}
};
template <typename T>
struct default_converter<T, T>
{
static inline T convert(const T& input)
{
return input;
}
};
template <typename ErasedType>
struct default_converter<std::string, ErasedType>
{
static inline std::string convert(const ErasedType& input)
{
default_converter<std::string, ErasedType>::prepareConverter();
default_converter<std::string, ErasedType>::converter << input;
return default_converter<std::string, ErasedType>::converter.str();
}
static inline ErasedType convert(const std::string& input)
{
default_converter<std::string, ErasedType>::prepareConverter(input);
ErasedType result;
default_converter<std::string, ErasedType>::converter >> result;
return result;
}
private:
static std::stringstream converter;
struct SetExceptionFlagsOnce
{
SetExceptionFlagsOnce()
{
default_converter<std::string, ErasedType>::converter.exceptions(std::stringstream::failbit);
}
};
static void inline prepareConverter(std::string value = "")
{
static SetExceptionFlagsOnce setter;
default_converter<std::string, ErasedType>::converter.clear();
default_converter<std::string, ErasedType>::converter.str(value);
}
};
template <typename ErasedType>
std::stringstream default_converter<std::string, ErasedType>::converter;
template <>
struct default_converter<std::string, std::string>
{
static inline std::string convert(const std::string& input)
{
return input;
}
};
}
#endif // CONVERTIBLETO_CONVERTERS_H
main.cpp:
#include <iostream>
#include "convertibleTo.h"
int main()
{
int I = 5;
convertibleTo< std::string > i(I);
std::cout << i.get() << std::endl;
i.set("321");
std::cout << i.get() << std::endl;
return 0;
}
Error I'm getting is:
RTTI symbol not found for class 'convertibleTo<std::string, convertibleTo_detail::default_converter>::holder<int>'
it's shown when I go inside i.get(), and then inside holder's get().
EDIT: Moved the full source from pastebin here, as per suggestion
Since the last two comments suggested that this is a GDB bug, how do I check this myself next time?
In case GDB complains about missing vtable - would confirming that I can access every virtual member through a reference to ABC initialized with derived class be enough to confirm that everything is OK?
In case GDB complains about missing RTTI symbol - would calling typeid() on the reference to ABC initialized with derived class to be enough to confirm that the RTTI symbol is, in fact, present?

Your code (the full version, with two header files and main.C) compiles and links without any errors for me, with gcc 4.8.3, with the default options (except for -std=c++11, to enable C++11 mode).
I even loaded the resulting executable into gdb. gdb swallowed it without any issues.
I don't see anything wrong here.

Related

How to pass a C++ Template instance to a function?

How can I pass any object of an templated class to another function in C++11?
In the snippet below passInObj does not compile because it complains about Printer&. I want to pass in any Printer it does not matter which template T I have used.
How can I do this and why does the solution below not work?
#include <iostream>
#include <vector>
template <typename T>
class Printer {
public:
Printer(const T& tl) : t(tl) {}
void print() const {
for (auto x : t) {
std::cout << x << std::endl;
}
}
const T &t;
};
// THIS LINE DOES NOT COMPILE
void passInObj(const Printer& p) {
p.print();
}
int main() {
std::vector<std::string> vec;
vec.push_back("ABC");
Printer<std::vector<std::string>> printer(vec);
printer.print();
passInObj(p);
return 0;
}
How can I do this
You need to make it into a function template:
template <class T>
void passInObj(const Printer<T>& p) {
p.print();
}
Demo
and why does the solution below not work?
Because Printer is not a type, it's only a template. For passInObj to work with any Printer<T>, you need to make the function into a function template so that it'll be instantiated for every Printer<T> which is used to call it.
While #TedLyngmo's answer should be your go-to by default, you can also do this via a polymorphic interface if you cannot make passInObj() a template for some reason or other.
This is done by adding a base interface class that will be derived by all Printer<> classes:
#include <iostream>
#include <vector>
class IPrinter {
public:
virtual void print() const = 0;
// Either that or public and virtual
protected:
~IPrinter() = default;
};
template <typename T>
class Printer : public IPrinter {
public:
Printer(const T& tl) : t(tl) {}
void print() const override {
for (auto x : t) {
std::cout << x << std::endl;
}
}
const T &t;
};
void passInObj(const IPrinter& p) {
p.print();
}
int main() {
std::vector<std::string> vec;
vec.push_back("ABC");
Printer<std::vector<std::string>> printer(vec);
printer.print();
passInObj(p);
return 0;
}

Template functions by index in C++

Suppose I have a class in C++11 like this:
class Something
{
...
private:
class1* a;
class2* b;
class3* c;
public:
class1* reada() { return a; }
class2* readb() { return b; }
class3* readc() { return c; }
void customFunctionForclass1();
void customFunctionForclass2();
void customFunctionForclass3();
}
}
I'd like to make the read functions templated so that if another programmer adds another member class, the corresponding read function will be template-magic created.
Something like this maybe?
class Something
{
...
private:
templateContainer = {class1*,class2*,class3*}
template<thing in templateContainer>
thing variableOfTypeThing;
public:
template<thing in templateContainer>
<thing> read() {return variableOfTypeThing<thing>;}
void customFunctionForclass1();
void customFunctionForclass2();
void customFunctionForclass3();
}
As you can tell from the example, I'm confused.
Basically, I have a class which acts as a container for guaranteed unique class variables (no class1 A; class1 B)
Some function groups for the class are almost identical some function groups are highly varied. It would be great for future people to only have to modify the different parts of the class and get the rest from the templates.
I thought maybe there would be a way by splitting this class up into lots of classes and stuffing them into an array of void pointers, but that seems unwise.
Suggestions?
I'd like to make the read functions templated so that if another programmer adds another member class, the corresponding read function will be template-magic created.
You could encapsulate the user defined classes in a thin wrapper class with a read() function that returns the contained instance. Adding a user defined class to Something would then be done by inheriting wrapper<user_defined_class>.
Basically, I have a class which acts as a container for guaranteed unique class variables
Inheriting this wrapper prevents you from including the same class twice so it could possibly be a way forward:
#include <iostream>
// the "thing" wrapper
template<typename T>
struct thing {
// forward construction arguments to the contained variable
template<class... Args>
thing(Args&&... args) : variable(std::forward<Args>(args)...) {}
// basic interface, const and non-const. I called it get() instead of read()
T const& get() const { return variable; }
T& get() { return variable; }
private:
T variable;
};
// a troublesome user defined class that is not default constructibe :-(
struct user_defined {
user_defined() = delete; // silly example really, but it's just to demonstrate
user_defined(const std::string& v) : str(v) {}
user_defined& operator=(const std::string& v) {
str = v;
return *this;
}
std::string const& say() const { return str; }
private:
std::string str;
};
std::ostream& operator<<(std::ostream& os, const user_defined& ud) {
return os << ud.say();
}
// ... and the "Something" class that inherits the wrapped types.
class Something : thing<int>,
thing<double>,
thing<user_defined>
{
public:
// add initial values for types that are not default constructible
Something(const std::string& val) : thing<user_defined>(val) {}
Something() : Something("") {} // default ctor
// access via derived class, const and non-const
template<typename T>
T const& get() const {
return thing<T>::get(); // get() from the correct base
}
template<typename T>
T& get() {
return thing<T>::get(); // get() from the correct base
}
};
void print(const Something& s) {
// using the const interface
std::cout << s.get<int>() << "\n";
std::cout << s.get<double>() << "\n";
std::cout << s.get<user_defined>() << "\n";
}
int main() {
Something foo;
// using the non-const interface to set
foo.get<int>() = 10;
foo.get<double>() = 3.14159;
foo.get<user_defined>() = "Hello world";
print(foo);
}
Edit: It doesn't fulfill the index part of your question though. You access it using the type you'd like to get() as a tag. You basically build a very rudimentary tuple I guess.
Code based on #Ted Lyngmo's answer:
#include <iostream>
#include <string>
template<typename T>
struct thing {
// forward construction arguments to the contained variable
template<class... Args>
thing(Args&&... args) : variable(std::forward<Args>(args)...) {}
// basic interface, const and non-const. I called it get() instead of read()
T const& get() const { return variable; }
T& get() { return variable; }
protected:
T variable;
};
template<typename ...Ts>
struct things : thing<Ts>... {
template<class... SubTs>
things(thing<SubTs>&&... ts) : thing<SubTs>(std::move(ts))... {}
// access via derived class, const and non-const
template<typename T>
T const& get() const {
return thing<T>::get(); // get() from the correct base
}
template<typename T>
T& get() {
return thing<T>::get(); // get() from the correct base
}
};
// a troublesome user defined class that is not default constructibe :-(
struct user_defined {
user_defined() = delete; // silly example really, but it's just to demonstrate
user_defined(const std::string& v) : str(v) {}
user_defined& operator=(const std::string& v) {
str = v;
return *this;
}
std::string const& say() const { return str; }
private:
std::string str;
};
struct non_default {
non_default() = delete;
non_default(int) {}
};
std::ostream& operator<<(std::ostream& os, const user_defined& ud) {
return os << ud.say();
}
// ... and the "Something" class that inherits the wrapped types.
class Something : public things<int, double, user_defined, non_default>
{
public:
// add initial values for types that are not default constructible
Something(const std::string& val) : things(thing<user_defined>(val), thing<non_default>(0)) {}
Something() : Something("") {} // default ctor
};
void print(const Something& s) {
// using the const interface
std::cout << s.get<int>() << "\n";
std::cout << s.get<double>() << "\n";
std::cout << s.get<user_defined>() << "\n";
}
int main() {
Something foo;
// using the non-const interface to set
foo.get<int>() = 10;
foo.get<double>() = 3.14159;
foo.get<user_defined>() = "Hello world";
print(foo);
}

Specialized inheritance of a templated class causes member function to return templated class type rather than inherited class type

Assume I have a base class like this:
template<typename T>
class Base {
public:
Base& operator()(const T& value) {
this->value = value;
return *this;
}
T value;
};
Now I want to inherit from this class to create type-specific classes
class InheritedFloat : public Base<float> {} inheritedFloat;
Now here I try to catch this inheritance in a functon:
void function(const InheritedFloat& inherited) {
std::cout << inherited.value << '\n';
}
Calling this function like this works fine, of course:
int main() {
function(inheritedFloat); //(inheritedFloat is a global instance)
return 0;
}
But when I try to call it with the operator()(const float& value){...} member function, function(const InheritedFloat& inherited){...} doesn't see it as a InheritedFloat-Type but instead as a Base<float>-Type:
int main() {
function(inheritedFloat(10.f)); //error
return 0;
}
Error:
Error C2664 'void function(const InheritedFloat &)': cannot convert argument 1 from 'Base<float>' to 'const InheritedFloat &'
So how can I make operator()(const T& value){...} return InheritedFloat& instead of Base<float>&?
To clearify further, this is just a simplified example (of course). I have dozens of inheritance cases. So I can't just template-specify function()
template<typename T>
void function(const Base<T>& inherited) {
std::cout << inherited.value << '\n';
}
because each inheritance needs to be treated differently. Types will overlap, so there will be multiple Base<std::size_t> cases, for example.
The whole code:
#include <iostream>
template<typename T>
class Base {
public:
Base& operator()(const T& value) {
this->value = value;
return *this;
}
T value;
};
class InheritedFloat : public Base<float> {} inheritedFloat;
void function(const InheritedFloat& inherited) {
std::cout << inherited.value << '\n';
}
int main() {
function(inheritedFloat(10.f));
return 0;
}
Thanks for reading, I appreciate any help!
You can utilize CRTP here. By supplying extra template parameter you can make base class function return a reference to a derived class:
#include <iostream>
template<typename Derived, typename T>
class Base {
public:
Derived & operator()(const T& value) {
this->value = value;
return *static_cast<Derived *>(this);
}
T value;
};
class InheritedFloat : public Base<InheritedFloat, float> {} inheritedFloat;
void function(const InheritedFloat& inherited) {
std::cout << inherited.value << '\n';
}
int main() {
function(inheritedFloat(10.f));
return 0;
}
online compiler

Template class spezialisation missing member

I wanted to create a simple template class having a member variable ret. For some reason my MSVC 2010 compiler complains, that there is no declared variable named ret in Converter<double>. I'm really clueless, why?
template<typename M>
struct Converter {
M ret;
void operator()(const int& value) {
throw std::exception("Not implemented!");
}
};
template<>
struct Converter<double> {
void operator()(const int& value) {
ret=value;
}
};
int main() {
Converter<int> x;
}
This is another class (there is no inheritance or any other depenency here):
template<>
struct Converter<double> {
double ret;
void operator()(const int& value) {
ret=value;
}
};
I know this is already marked solved, but I thought I should just clarify this further.
Converter<double> and Converter<int> are different separate classes, so ret would not be defined in your double variation until you declare it as one of its members.
Regardless, it appears what you're trying to achieve is inheritance, which can be done in a similar way:
template<typename M>
struct AbstractConverter { // you could call it 'Converter' too, and it'll work as you expect
M ret;
virtual void operator()(const int& value) {
throw std::exception("Not implemented!");
}
//or
virtual void operator(const int &value) = 0; //pure virtual
// will not compile if someone wants to use it directly
};
template<>
struct Converter<double> : public AbstractConverter<double>{
void operator()(const int& value) { // we implement the operator here
ret=value;
}
};

How to call function in derived if exists else use a default if using CRTP?

I have a helper base class for certain structs that uses CRTP to help me get some information about them:
template <class T>
struct MyHelper
{
size_t size() const { return sizeof(T); }
};
I already have structs using this defined in various libraries in my code base, and I would like to have a way to log them. My first idea was something like this:
template <class T>
struct MyHelper
{
size_t size() const { return sizeof(T); }
virtual void print(std::ostream& out) const { out << "(" << sizeof(T) << ")"; }
};
but then I realized that wouldn't work for a couple reasons - one of them being adding virtual actually changes the size beyond just the POD data.
Is there a way, without the virtual keyword, for me to have a default toStr method which uses the above implementation unless the particular derived class T has an implementation in which case it defers to that?
I think the most straightforward way to do something like this is to dispatch to a different non-virtual function that the derived class can shadow if it so desires. For example:
template <class T>
struct MyHelper
{
size_t size() const { return sizeof(T); }
void print(std::ostream &out) const {
// Cast to derived, call do_print. This will be derived's do_print
// if it exists and MyHelper's otherwise.
static_cast<T const*>(this)->do_print(out);
}
void do_print(std::ostream& out) const {
out << "(" << sizeof(T) << ")";
}
};
struct A : MyHelper<A> {
// no do_print, so MyHelper<A>'s will be used
int x;
};
struct B : MyHelper<B> {
// B's do_print is found and used in MyHelper<B>::print
void do_print(std::ostream &out) const {
out << "Hello!\n";
}
};
template<typename T>
void foo(MyHelper<T> const &r) {
r.print(std::cout);
}
int main() {
A a;
B b;
foo(a);
foo(b);
}
Output:
(4)Hello!
You could probably also build something with SFINAE that doesn't need a second member function, but I doubt the added complexity would be worth it.