So I am trying to do something, but I am not sure it can/should be done this way in c++.
I have a file of objects I want to read in. Each object is of one of 3 types of classes which are part of a hierarchy
In the file I have a discriminator to tell me which is which.
Lets say the classes are:
Checking, Savings and are subclasses of Account.
Can i build code such that:
Account a;
istream >> a;
Will let me polmorphically set the resulting data in a to the appropriate type ?
( i realize the code would have to be there to do it)
Hope that makes sense. Or, do i just need a "deserialize" method or something that i don't use operator overloading for?
I can't use any existing non STL libraries out there, as this is for a classroom example.
Thanks!
Edit: I think my question may have been unclear:
friend istream& operator>>(istream& is, Transactions& transactions)
{
is my function, and i want to have transaction set to a subclass of Transaction....
I'm thinking this isn't possible without some of the new newer features
some have mentioned?
If you want polymorphism you need pointers or references. Objects are always the type you declare them as. Nothing more, nothing less.
So you need a separate factory function that can decide which type to create at runtime. For example, it could look something like this:
std::unique_ptr<Account> read_account(std::istream& is)
{
std::string type = read_type(is);
if (type == "checking") {
auto acct = std::make_unique<Checking>();
is >> *acct;
return acct;
} else {
auto acct = std::make_unique<Savings>();
is >> *acct;
return acct;
}
return {}; // or throw
}
C++ does not work this way, on a fundamental level. Quoting from your question, if you have a declaration:
Account a;
Then that's what a is. In C++, the types of all objects must be known at compile time. This is fundamental to C++, there are no exceptions or workarounds. The type of a cannot be changed at runtime, based on some arbitrary criteria.
Will let me polmorphically set the resulting data in a to the
appropriate type ?
Nope. a is an Account. This is immutable, and cannot be changed based on runtime conditions.
Or, do i just need a "deserialize" method
That would be a very common approach, and was pretty much the rule of the land before C++17.
In C++17 you could declare an
std::variant<std::monostate, Checking, Savings> a;
And then define an implement a >> for this, which will replace the default-constructed a monostate with an instance of one or the other class.
Note that the type of the object a is still fixed, and no rules are broken: a is a variant type. It has a specific type that's defined at compile-time.
Related
In my code, I have several class, each with different methods. For example:
class A {
public:
int sum(int a, int b);
bool isScalable(double d);
}
class B {
public:
std:string ownerName();
}
My aim is to create a map of all the function names as below
std::map<std::string, FnPtr> myMap;
// Add the newly implemented function to this map
myMap["sum"] = &A::sum;
myMap["isScalable"] = &A::isScalable;
myMap["myMap"] = &B::myMap;
The issue is I am not aware how I can define FnPtr. Can you please help me out.
As comments suggest, it is unlikely you really want to do this.
Assuming that you do, however - perhaps you should reconsider whether C++ is the right language for the task. Another language which has better runtime reflection facility might be more appropriate; perhaps an interpreted language like Python or Perl. Those are typically much more convenient when you need to look up class methods by name at runtime.
If it has to be C++, then perhaps you should relax the class structure somewhat. Use a single class for both A's and B's (lets call it MyCommonObj); and have the class hold a map of strings to function pointers. As for these functions' signatures - It's probably a good idea not to make the member functions, but freestanding ones. In that case, perhaps your function pointer type would be:
using generic_function = std::any (*)(std::vector<std::any>);
That's pretty generic - for storage and for invocation. If you have this map, you can easily look up your function name and pass the arguments. However, you might need to also keep additional information about what type your arguments should be, otherwise you'll always be passing strings. ... which is also an option, I suppose:
using generic_function = std::any (*)(std::vector<std::string>);
Now if the A and B members in your example are really non-static like you listed them, i.e. they use instance fields, then these generic functions must also always take a reference or pointer to an instance of MyCommonObj:
using generic_function = std::any (*)(MyCommonObj&, std::vector<std::string>);
Finally, note that code using this type, and run-time lookup of function names etc - will not be very performant.
If you're not using C++17 and don't have access to std::any, you can either:
Use boost::any from the Boost libraries.
Use an any-emulator library (which exist on GitHub)
Use a union of all the types you actually use, e.g. union {int i; double d;} - but then you'll need to protect yourself against passing values of the wrong type.
I was trying to write down some implementations for a couple of data structures that I'm interested in for a multithreaded / concurrent scenario.
A lot of functional languages, pretty much all that I know of, design their own data structures in such a way that they are immutable, so this means that if you are going to add value to an instance t1 of T, you really get a new instance of T that packs t1 + value.
container t;
container s = t; //t and s refer to the same container.
t.add(value); //this makes a copy of t, and t is the copy
I can't find the appropriate keywords to do this in C++11; there are keywords, semantics and functions from the standard library that are clearly oriented to the functional approach, in particular I found that:
mutable it's not for runtime, it's more likely to be an hint for the compiler, but this keyword doesn't really help you in designing a new data structure or use a data structure in an immutable way
swap doesn't works on temporaries, and this is a big downside in my case
I also don't know how much the other keywords / functions can help with such design, swap was one of them really close to something good, so I could at least start to write something, but apparently it's limited to lvalues .
So I'm asking: it's possible to design immutable data structure in C++11 with a functional approach ?
You simply declare a class with private member variables and you don't provide any methods to change the value of these private members. That's it. You initialize the members only from the constructors of the class. Noone will be able to change the data of the class this way. The tool of C++ to create immutable objects is the private visibility of the members.
mutable: This is one of the biggest hacks in C++. I've seen at most 2 places in my whole life where its usage was reasonable and this keyword is pretty much the opposite of what you are searching for. If you would search for a keyword in C++ that helps you at compile time to mark data members then you are searching for the const keyword. If you mark a class member as const then you can initialize it only from the INITIALIZER LIST of constructors and you can no longer modify them throughout the lifetime of the instance. And this is not C++11, it is pure C++. There are no magic language features to provide immutability, you can do that only by programming smartly.
In c++ "immutability" is granted by the const keyword. Sure - you still can change a const variable, but you have to do it on purpose (like here). In normal cases, the compiler won't let you do that. Since your biggest concern seems to be doing it in a functional style, and you want a structure, you can define it yourself like this:
class Immutable{
Immutable& operator=(const Immutable& b){} // This is private, so it can't be called from outside
const int myHiddenValue;
public:
operator const int(){return myHiddenValue;}
Immutable(int valueGivenUponCreation): myHiddenValue(valueGivenUponCreation){}
};
If you define a class like that, even if you try to change myHiddenValue with const_cast, it won't actually do anything, since the value will be copied during the call to operator const int.
Note: there's no real reason to do this, but hey - it's your wish.
Also note: since pointers exist in C++, you still can change the value with some kind of pointer magic (get the address of the object, calc the offset, etc), but you can't really help that. You wouldn't be able to prevent that even when using an functional language, if it had pointers.
And on a side note - why are you trying to force yourself in using C++ in a functional manner? I can understand it's simpler for you, and you're used to it, but functional programming isn't often used because of its downfalls. Note that whenever you create a new object, you have to allocate space. It's slower for the end-user.
Bartoz Milewski has implemented Okasaki's functional data structures in C++. He gives a very thorough treatise on why functional data structures are important for concurrency. In that treatise, he explains the need in concurrency to construct an object and then afterwards make it immutable:
Here’s what needs to happen: A thread has to somehow construct the
data that it destined to be immutable. Depending on the structure of
that data, this could be a very simple or a very complex process. Then
the state of that data has to be frozen — no more changes are
allowed.
As others have said, when you want to expose data in C++ and have it not be available for changing, you make your function signature look like this:
class MutableButExposesImmutably
{
private:
std::string member;
public:
void complicatedProcess() { member = "something else"; } // mutates
const std::string & immutableAccessToMember() const {
return member;
}
};
This is an example of a data structure that is mutable, but you can't mutate it directly.
I think what you are looking for is something like java's final keyword: This keyword allows you to construct an object, but thereafter the object remains immutable.
You can do this in C++. The following code sample compiles. Note that in the class Immutable, the object member is literally immutable, (unlike what it was in the previous example): You can construct it, but once constructed, it is immutable.
#include <iostream>
#include <string>
using namespace std;
class Immutable
{
private:
const std::string member;
public:
Immutable(std::string a) : member(a) {}
const std::string & immutable_member_view() const { return member; }
};
int main() {
Immutable foo("bar");
// your code goes here
return 0;
}
Re. your code example with s and t. You can do this in C++, but "immutability" has nothing to do with that question, if I understand your requirements correctly!
I have used containers in vendor libraries that do operate the way you describe; i.e. when they are copied they share their internal data, and they don't make a copy of the internal data until it's time to change one of them.
Note that in your code example, there is a requirement that if s changes then t must not change. So s has to contain some sort of flag or reference count to indicate that t is currently sharing its data, so when s has its data changed, it needs to split off a copy instead of just updating its data.
So, as a very broad outline of what your container will look like: it will consist of a handle (e.g. a pointer) to some data, plus a reference count; and your functions that update the data all need to check the refcount to decide whether to reallocate the data or not; and your copy-constructor and copy-assignment operator need to increment the refcount.
i have a design issue, not complicated actually, but i would like to find an elegant way to solve it. And i thought about this:
Issue:
i have a class A that initialize and keep a collection of B
B is just an interface and must be implemented (so we have classes C,D,E,..).
in constructor A recive a bunch of dataset and must initialize some of B (also lot of different instantiation of same or different class) given each dataset. I would like A to not to know any implementation of B.
I have several working solution, but i was thinking about a kind of "delegate in the constructor".
eg:
1. for each dataset, ds
2. for each implementation of B, bi
3. try to instantiate bi(ds)
4. if success (means no exception)
5. keep reference
this because the data and calculus i use to check if bi are pretty the same of initialization and being in a performance-critic application i would like to avoid doing that twice or doing it in collection class.
it would be really nice but obviously the problem is line 2...
...as well as the doubt about using exception for something that is not actually an exception. (line 4)
so what should be a pattern that
- let me evaluate data and construct all in one.
- avoid creating several "architectural-classes" i would like to avoid an explosion of classes ( kind of typical when exagerating with following design patterns java-style principles imho ) for such a simple task.
- as fast as possible.
- ...is elegant :)
The answer is based on my intuition right now, so it may not be perfect, but on the other hand, most of the design solutions aren't.
I would create just one additional class, call it factory or something similar. Then run all the constructions through this class. It should be able to be initialized with possible instantiations of derives of B either in run-time (by running callbacks at the beginning of the program), or, even better, by variadic template traits.
template<class ... RegisteredBImplementations>
class CFactory
{
B* Create (dataset const& d)
{
// some magical meta-ifs to create compile time conditions
// or for (auto& registered_type : registered types), and then choose one
return new T(d);
}
}
Then, A could use an instance of this class to initialize it's pointers properly:
for (auto& dataset : datasets)
{
m_BPtrs.emplace_back( std::unique_ptr<dataset> (m_FactoryInstance.Create(dataset)) );
}
The main point of this solution is that class A effectively manages "B" objects, leaving proper construction of them to the other class. They are effectively separated, and addition of a new B implementation means a change only in CFactory, not in A.
Your pseudocode suggests a solution: your use of bi is nothing more than a factory function that takes a dataset as input and returns a B* as output. So, you really just need to take bi from a collection of std::function<B* (dataset)> objects.
It would be easy enough to require that these factories are only 'conditional' factories: that sometimes they return valid objects, and sometimes they don't, returning nullptr instead. This would let you avoid exceptions, and is more faithful to the intent of your usage.
The simplest solution is to delegate to a Factory method.
std::unique_ptr<B> build(DataSet const& ds) {
if (ds.property() == value) {
return std::unique_ptr<B>(new D(ds));
}
return std::unique_ptr<B>(new C(ds));
}
Then A need only depend on the declaration of build.
I already figured out to use polymorphism and have the list store the pointer to the baseClass, but after successfully placing it there, I would like to know what class the object was originally. I am using templates for the classes, and wanted to have an another field which would be an enum of basic types.
Now the question: is there a way to check (during runtime or during compilation) an
(if T == int)
field = INT
I though maybe something with the preprocessor but I'm not familiar with that.
The whole idea behind polymorphism is to hide the specific implementation making it transparent in your program flow. Using type of class as an indicator will make your code bloat with if statements and will be harder to maintain.
I suggest you reconsider your design and make an abstract class with the intended behavior methods and use this class type as the list objects type. Than for each object call the interface method (which was declared in the abstract class and implemented in the deriving classes)
You can use operator typeid.
For example, if T is a pointer to a base class:
if (typeid(SomeDerivedClass) == typeid(*T))
...
(It is somewhat unclear for me why you speak about int in connection with polymorphism. int cannot be derived from.)
What you are probably looking for is known as type traits. They allow you to determine and act on the attributes of a specific type. You could start with std::is_integral() and std::is_floating_point() and build from there depending on your requirements.
enum Type
{
Unknown,
Integral,
Float
};
....
Type field = Unknown;
if(std::is_integral<T>::value)
{
field = Integral;
}
else if(std::is_floating_point<T>::value)
{
field = Float;
}
The C++ preprocessor knows nothing about C++. It is a generic symbol manipulator which can be used with most any programming language, or for that matter, any text processing application, such as a feature of word or equation layout processing.
You might look into the typeid operator as one way to build such a mechanism, though heed the Misuses of RTTI section further down on that page.
I was implementing a dynamic typing library for D when I ran across an interesting problem.
Right now, I've succeeded in making a function called dynamic() which returns a dynamic version of an object.
For example:
import std.stdio, std.dynamic.core;
class Foo
{
string bar(string a) { return a ~ "OMG"; }
int opUnary(string s)() if (s == "-") { return 0; }
}
void main(string[] argv)
{
Dynamic d = dynamic(new Foo());
Dynamic result = d.bar("hi");
writeln(result); // Uh-oh
}
The problem I've run across is the fact that writeln tries to use compile-time reflection to figure out how to treat result.
What's the first thing it tries? isInputRange!(typeof(result))
The trouble is, it returns true! Why? Because I have to assume that all members which it needs exist, unless I can prove otherwise at run time -- which is too late. So the program tries to call front, popFront, and empty on result, crashing my program.
I can't think of a way to fix this. Does anyone have an idea?
You are trying to make two fundamentally different concepts work together, namely templates and dynamic typing. Templates rely very much on static typing, isInputRange works by checking which attributes or methods a type has. Your dynamic type is treated as having every attribute or method at compile time, ergo it is treated as fulfilling every static duck-typing interface.
Therefore, to make Dynamic work in a statically typed environment, you have to provide more static information at some places.
Some solutions I can see:
provide your own dynamically typed implementations for heavily used functions. The whole problem you are having is caused by the fact that you are trying to use generic functions that assume static typing with dynamic types.
explicitly make dynamic a range of char, and care for the conversion to string of the underlying data yourself. (You'd have to have a custom toString method anyways if the isInputRange issue would not exist, because otherwise its result would again be of Dynamic type). This would probably make writeln(d); work.
provide wrappers for dynamic that allow you to pass dynamic types into various templated functions. (Those would just exhibit a static interface and forward all calls to Dynamic).
Eg:
Dynamic d;
// wrap d to turn it into a compile-time input range (but NOT eg a forward range)
Dynamic d2=dynamic(map!q{a*2}(dynInputRange(d)));
// profit
4 . Add a member template to Dynamic, which allows to statically disable some member function names.
Eg:
static assert(!isForwardRange!(typeof(d.without!"save")));
what is wrong with using std.variant which implements all you need for dynamic typing (along with quite a bit of syntactic sugar)
Could you provide an overload for isInputRange? Something like this (note that I haven't looked at the implementation of isInputRange):
template isInputRange(T : Dynamic) {
enum isInputRange = false;
}
If this is provided by your dynamic.core, I think this overload should be chosen before the std lib one.
For the general case Dynamic has to accept any method lookup at compile time, as you said. Suppose for a moment that you could prevent the isInputRange predicate to evaluate to true, now the wrong code will be generated when you try to create a Dynamic from an input range.
I don't think this is fixable, at least not in a general way. In this particular case the best solution I can think of is that Dynamic provides it's own version of toString, and writeln would prefer that over the inputRange specialization. I believe writeln doesn't do this at the moment, at least not for structs, but it probably should.
Another compromise would be to disallow a few methods such as popFront in the opDispatch constraint, instead Dynamic would provide opIndex or a member object to access these special cases. This might not be as bad as it sounds, because the special cases are rare and using them would result in an obvious compiler error.
I think that the best way to salvage this kind of method resolution for Dynamic is to fix writeln and accept that Dynamic will not work with all templated code.
Have you looked into std.variant?
import std.stdio, std.variant;
class Foo {
string Bar(string a) {
return a ~ " are Cool!";
}
}
void main() {
Variant foo = new Foo();
Variant result = foo.peek!Foo.Bar("Variants");
writeln(result); // Variants are Cool!
}
http://www.d-programming-language.org/phobos/std_variant.html