Template function for collection based on member - c++

I have the following structures
struct Obj
{
int a;
int b;
};
class ObjCollection
{
map<int,Obj> collMap;
public:
string getCsvA();
string getCsvB();
};
getCsvA returns a csv of all the a values in the objects of collMap. getCsvB returns the same for all the b values.
Is there a way I can template this function? The reason it becomes complicated for me is that i cannot pass the address of which member i want to generate the csv for, from outside this class ie from my client code. Is there a way to do this?
Note: I can not use C++11.

This looks like you need a function as a parameter to getCsv rather than templates:
Declare the function as string getCsv(int (*selectMember)(Obj)). Furthermore use selectMember([...]) wherever you would have used [...].a in getCsvA.
Now you can call getCsv providing a method returning the right field of Obj, for example:
int selectA(Obj o)
{
return o.a;
}

While a bit inelegant, if you've just a couple fields you can reasonably have getCsvA and getCsvB call a getCsv(A_or_B a_or_b) function, given enum A_or_B { A, B };, then inside getCsv when you you're iterating over collMap say int value = (a_or_b == A) ? iterator->a : iterator->b;, then you put that value into your csv string. Easier than worrying about pointers to member data, functors or templates: when you're comfortable with this level of programming, then you can worry about more abstract approaches (hopefully you'll have C++11 available then, as lambdas are nice for this).

The skeleton of code that you have actually looks okay. It's generally a bad idea to parameterize things that aren't necessary to parameterize. Templates are the most powerful way, but they should really be used with equal discretion.
By adding parameters, you add more opportunities for incorrect code (incorrect function pointer, null pointer, etc...). Using function pointers or virtual methods also creates more difficulty for the compiler in optimizing, since the code executing generally has to be resolved at runtime.
If you were using C++11 instead of C++03 though, using a std::tuple instead of a naked struct would probably make sense, and you would get a templated function as a bonus.
#include <utility>
template<typename... Ts>
class TupleCollection {
public:
template<std::size_t I>
std::string getCsv() {
for (const auto& p : collMap) {
std::string v = static_cast<std::string>(std::get<I>(p.second));
...
}
}
private:
std::map<int, std::tuple<Ts...>> collMap;
};
Then getting the CSV for the relevant field in a compile time safe way would be
tc.getCSV<0>();
tc.getCSV<1>();

Related

Can you use a string(or c string) as a typename [duplicate]

This question already has answers here:
Is there a way to instantiate objects from a string holding their class name?
(12 answers)
Closed last year.
I have a map loading function that takes input using ifstream from a file and creates objects from them.
Here is what the file might look like:
tree=50,100,"assets/tree.png"
box=10,10,"assets/box.png"
Which should create the objects tree and box and pass the values to their constructor. I already have the value part figured out, but I don't know how to take the string "tree" and create a tree object.
Is it possible to take a string(or c string) and use it as a type name?
Things I've tried:
Passing the string as a template typename
#include <string>
struct A {};
template<typename T>
T* createType() {
T* type = new T()
return T;
}
int main() {
std::string tname = "A";
auto* type = createType<tname>;
}
Using the using keyword
#include <string>
template<std::string T>
struct someType {}
struct A {};
struct B {};
using someType<"A"> = A;
using someType<"B"> = B;
int main() {
std::string tname1 = "A";
std::string tname2 = "B";
someType<tname1> typeA;
someType<tname2> typeB;
}
Problems:
I can't seem to find a clear answer about this but is seems like there are some problems with using a string as a template parameter.
I don't know if it is ok to pass a variable as a template parameter
I don't think that you can cast template types (from string to typename)
Is there any way that either of these, or some other way might work to accomplish this? Or is this just not possible?
No. As far as I know, there is no provision in C++ for finding types from an in-language string of any kind.
As for your other problems:
A value template parameter must be constexpr: since C++11, you can use variables of some constexpr types as template parameters
Apparently you can use a constexpr string_view template parameter in C++17, and a constexpr string template parameter in C++20
Regardless of these other answers, you still can't turn those strings into types. That kind of operation is typical of dynamic languages, but C++ is a statically typed, compiled language. And, while it is possible to design a static language that can do that kind of operation at compile time, that is not the path that C++ design has taken.
I think it's reasonable to ask: why you want to do this in the first place? There is probably a better way to accomplish whatever prompted the question, but without further information it is hard to know how to help.
Edit, in response to updated question:
In order to read datastructures from a file, you will need do the string-to-type mapping yourself.
Generally, you will have some "driver" object where you register types that you want to create from your file, which it will then use when reading from the file.
The simplest way is to register each typename in association with a callback to construct the data. The most straightforward, object-oriented way to handle the resulting heterogeneous datastructures is to derive all their types from a common Readable base class.
Registration is where you will provide the typename to be used in the file. If you don't feel like repeating the typename with every registration line, you can use macros to do that -- something like:
#define REGISTER(type) (driver.register(#type, &(type)::construct))
(note that #name is the C preprocessor's "string-izing" syntax)

Switching between two typedef structs, depending on boolean

I have a class with different functions. This class uses two typedef structs.
typedef struct {
struct head;
struct data1;
} data_struct_1;
typedef struct {
struct head;
struct data2;
} data_struct_2;
If a bool is true the data_struct_2 should be used, otherwise data_struct_1. The boolean is passed, when the object is created and stored as a membervariable in the constructor.
There are now different functions and declarations like
int calc_mean(data_struct_1 ds, int a){ ... }
or
data_struct_1 ds;
ds.data1 = 5;
Is there an elegant way, which allows me to switch between those two structs without implementing dozens of if-cases and duplicate all the relevant functions with the corresponding struct in the header?
First I was thinking about inheritance and overwritting relevant functions if bool is true.. but the header in the functions differs, so this wouldnt work
Maybe there is something like a placeholder or template, but i'm pretty new to c++
If boolean is compile-time value, std::conditional might be used:
template <boolean B>
using my_type = std::conditional_t<B, data_struct_1, data_struct_2>;
but it seems the boolean is runtime value, so I would use std::variant and std::visit:
class C
{
using Data = std::variant<data_struct_1, data_struct_2>;
Data m_data;
public:
C(bool b) : m_data{b ? Data{data_struct_1{}} : Data{data_struct_2{}}} {}
auto mean() const {
return std::visit([](const auto& data){ return calc_mean(data, 42); }, m_data);
}
};
You have a couple of options:
If the types are conceptually the same type of thing (i.e. they have the same interface and could be substituted for one another), you can:
Create an abstract base type and use polymorphism to change which concrete type is instantiated
Change all places that use these types into templates, change which template(s) are instantiated at runtime, and then rely on compile-time "duck-typing" to do the rest
If the types are conceptually different (i.e. they should not have the same interface), you can use a union type (union, std::variant).
Take a look at std::variant.
A variant can hold a number of alternative types, like this:
std::variant<data_struct_1, data_struct_2> m;
The member m can contain either a data_struct_1 or a data_struct_2. The variant will remember which, so there's no need for you to carry that bool around anymore.
The interesting question is now, how do you treat m in your functions? After all, it could be either a data_struct_1 or a data_struct_2 in there. Instead of using branches for distinguishing these cases, variant uses visit: Whenever you encounter a point in the function that depends on the concrete type stored in m, you move that code into two overloaded functions: One function that handles the data_struct_1 case and another that handles the data_struct_2 case. The example on the visit cppreference page shows some possibilities for doing that with varying degrees of syntactic overhead.
The good thing about this approach is that it forces you to always handle both cases properly. You can't just go ahead and write an implementation for one case and then forget about the other, having it blow up later at runtime. It also encourages a style where you clearly separate common parts of your code from type-specific parts, which often results in a cleaner design in the long term.
One possibility is to use std::variant:
typedef std::variant<data_struct_1, data_struct_2> data_struct_1_or_2;
void foo(data_struct_1_or_2 ds) {
if (auto ds1 = std::get_if<data_struct_1>(&ds)) {
// use ds1, which is type data_struct_1*
} else if (auto ds2 = std::get_if<data_struct_2>(&ds)) {
// use d2, which is type data_struct_2*
} else {
throw std::logic_error("Unexpected value in variant");
}
}
void bar(data_struct_1_or_2 ds) {
foo(ds); // Don't need to use an if statement here
}
If you have a data_struct_1 or data_struct_2 and want to pass a reference to the object, rather than a copy, you could use pointers in the std::variant instead (although it'll get a bit confusing with std::get_if because you'll end up with a pointer to a pointer):
typedef std::variant<data_struct_1*, data_struct_2*> data_struct_1_or_2_ptr;
A simple C solution would be a union with a bool tag:
typedef struct {
struct head;
bool type_flag;
union{
struct data1 d1;
struct data2 d2
};
} data_struct;
std::variant is an overkill for this case IMO. Inheritance and runtime polymorphism is a waste of runtime and memory.
Regards,
FM.

Template function pointer parameter vs constructor argument

I have a dilemma about how I should pass a function pointer that will be used extensively by a class throughout the object lifetime. I have thought of 2 solutions:
Passing the function pointer to the constructor and storing it inside the class:
using Func = int(*)(int);
class A
{
public:
explicit A(int n, Func f)
: _f(f), _n(n)
{}
int Process()
{
return f(n);
}
private:
Func _f;
int _n;
};
Or using a template parameter:
using Func = int(*)(int);
template<Func f>
class A
{
public:
explicit A(int n)
: _n(n)
{}
int Process()
{
return f(n);
}
private:
int _n;
};
I think the template solution is more elegant but I am not really sure if it is the best solution.
And as a subsidiary question in the template solution, if only the Process method is using the template parameter can I still put the constructor in a source file and keep the Process method in the header file?
Passing f as a template parameter will result in a separate instantiation of the template for each different value of f. If the code size implications of this worry you, don't use a template. If not, and execution time is of paramount importance, then do.
An example of where using a template parameter can speed up execution is std::sort. If you pass a conventional function pointer for the comparison function (as in the C-style qsort), then the time to call it often accounts for a large part of the time to perform the sort. OTOH, std::sort can inline simple comparison functions, which is faster.
With minor exceptions, templates must be implemented in header files. This is a problem if you have and API and want to hide how a proprietary piece of code is implemented, for instance, as anyone could simply open the header and look at it.
It also could increase compile time, as the template class needs to get created by the compiler at compile time, vs. getting linked in by the linker.
If neither of these problems bother you, then templates are probably a good way to go here. For one, as you say, it is more eloquent and for another they are quite flexible. If you wake up tomorrow and want to use a different type of function pointer, you are quite free to do so.
Of course, the final decision is up to you, but hopefully now you know some of the pros and cons of each.
Edit: Somehow I missed the last part of your question.
So, any templated part of your code must go in the header. Since your whole class is templated, then you can't put it in a source file.
What you can do instead is make only function that accepts it as a parameter itself templated:
class A
{
public:
explicit A(int n); // an go in C++ now
template<Func f>
int Process()
{
return f(n);
}
// ...
};
However, doing it that way will allow Process to accept any function pointer independent of the class. That is, A is no longer bound to a specific f, but rather an individual call to Process is bound to an f. That may not be what you want. Instead, it may be better to do option 1 than my suggested option 3. But again, that's up to you.

Recycling member functionality without inheritance

There is an interesting template presented on Wikipedia for Properties.
This template provides something interesting, in that it allows providing logic around member accesses. Building on this, we could easily build something like this:
struct Ranged {
ranged_property<float,0,1> unit_property;
};
Where the range of unit_property is enforced to be within [0,1].
How can we provide a similar functionality the depends on the hosting class' members? For example:
struct AdjustableRanged {
float max;
ranged_property<float,0,max> influenceable_property;
};
Where the range of influenceable_property is affected by the value of max. Keep in mind, the goal is for this kind of template to be recycled across many vastly different classes. Related concepts are mixins and decorators.
It can be done with macros... but I feel like there must be a better more idiomatic C++ solution.
Edited to add: I think this could be done by saving a reference to the member inside the ranged_property template... but that seems to be a complete waste of space for what would be effectively a constant value; ETA; A const reference may serve the purpose actually, however, I need to do the investigation.
Following up on our discussion in the comments, it seems the functionality can be achieved with a pointer-to-member template parameter like this (but see the caveats below):
#include <iostream>
template<typename C, typename T, T C::*m>
struct PrintMember {
C& obj;
PrintMember(C& obj) : obj(obj) {};
void print() { std::cout << "Member of containing class: " << obj.*m << std::endl; };
};
struct TestClass {
int data;
PrintMember<TestClass, int, &TestClass::data> pm;
TestClass() : pm(*this){};
};
int main()
{
TestClass tc;
tc.data = 5;
tc.pm.print();
}
This only demonstrates that it is possible to access members of the containing object. There are a few things that this approach doesn't solve:
If you really only want to access one member, it's not worth it, since you have to save a reference to *this in the PrintMember member to be able to dereference the pointer to member. So it doesn't actually solve the problem of having to store a reference. You could just as well pass a reference to the member variable itself in the constructor. However, if you need to access multiple members, this allows you to only store one reference (to *this) and still access all of them.
Specifying the template arguments of PrintMember and initializing the PrintMember member variable with *this in the constructor is tedious. Maybe, some clever template argument deduction can help here, but I haven't tried yet and I am not even sure it would get any simpler...
In some special cases, there might be dirty ways to get access to the "this" pointer of the enclosing class without saving it explicitly, like the answer using offsetof in this answer, but my feeling tells me you wanted something portable and less brittle...

lambda as template parameter with access to 'this' pointer?

I have to create objects of three-four classes, all inherited from one base class, but some of the objects need to have different behavior - like complete change of one function; I can do this through more inheritance and polymorphism, but it doesn't seem like a good idea.
My first solution was to use specialized templates(for every nonstandard case), but then I have though about lambdas as template parameter(like here: Can we use a lambda-expression as the default value for a function argument? ) and use them instead class method(like here: C++11 lambda and template specialization ) - for me it's much better solution, because I only have to pass lambda for every weird situation:
auto default_lambda = [&]() -> int {return this->Sth;};
template<typename functor = decltype(default_lambda)>
class SomeClass{
...
Problem is with this pointer - method which I want to change need access to non-static methods and lambda is defined outside of non-static method. Moreover, I can't pass reference to class to lambda, because it's a template class(or maybe I'm wrong?).
Of course, I can use specialized template or just function pointers, but I really like solution with lambdas and I consider it much more fine than my other ideas.
Is there any way to "avoid" this problem? Or maybe my idea was bad all along?
There are at least three obvious problems with your approach:
The class SomeClass won't get access to private members, i.e. use of this is out of question.
You attempt to bind this from the context but there is no context i.e. nothing bind to. You will have to pass the object to dealt with a function parameter.
You only specified a type of the function object but no instance, i.e. you won't be able to use it later.
That said, it seems you could just use the type of a custom function object type rather than some lambda function (sure, this is absolutely unsexy but in return it actually works):
struct default_lambda {
template <typename T>
int operator()(T const& o) const { return o.x(); }
};
template <typename F = default_lambda>
class SomeClass {
...
};
If you need complete change of one function, you have two choices:
One virtual function, using perhaps local classes + type erasure if you have many such objects and you don't want to create many namespace scope types:
std::function, which can be rebound later if you wish.
Example code for the first solution (you can even make this a template):
std::unique_ptr<my_base2> get_an_object()
{
class impl : public my_base2
{
void my_virtual_function() { blah blah; }
};
return std::unique_ptr<my_base2>(new impl);
}
Both are generally superior to templates in this situation (but without context it is hard to tell).