Template parameter types as string

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Template parameter types as string

Post by Candy »

Is it possible to retrieve the types of a templatized function as a plain string, to pass them up to a different (next) layer?

Code: Select all

template <class S, class T> stream<S, T> *getModule() { 
     std::string firstArg, secondArg; 
     ???
     return reinterpret_cast<stream<S, T> *>(do_syscall(firstArg, secondArg));
}
I don't know what to put at those three question marks. It should be logically equivalent to the following code, but then functional (as in, also using the real types):

Code: Select all

firstArg = "S";
secondArg = "T";
So the eventual function upon compilation could become

Code: Select all

template <char, int> stream<char, int> *getModule() { 
     std::string firstArg, secondArg; 
     firstArg = "char";
     secondArg = "int";
     return reinterpret_cast<stream<char, int> *>(do_syscall(firstArg, secondArg));
}
Is this even possible?

I could pass them as arguments to getModule but that'd be very ugly and I am trying to prevent that.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:Template parameter types as string

Post by Candy »

OK, figured out a way to get the mangled name.

Code: Select all

#include <typeinfo>

template <typename A, typename B> stream<A, B> *getModule() {
    std::string firstArg, secondArg;
    firstArg = typeid(A).name();
    secondArg = typeid(B).name();
    return reinterpret_cast<stream<A, B>*>(do_syscall(firstArg, secondArg));
}
Tweel

Re:Template parameter types as string

Post by Tweel »

I think you can use typeid() on a template class to get the types it was instansiated with as as string. So...

Code: Select all

Foo<int> f;
std::cout << typeid(f).name() << std::endl;
Prints "class Foo<int>" (in VC++ at least, i think GCC returns something different but similar). So you'd need to parse that somehow.
proxy

Re:Template parameter types as string

Post by proxy »

another approach besides typeid would be template specializations which take a type paramter..for example:

Code: Select all

template<class T> struct type_from_size;

template <> struct type_from_size<int> {
    typedef int value_type;
    static const std::string type_name;
};

std::string type_from_size<int>::type_name = "int";
then you can do:

Code: Select all

std::cout << type_from_size<int> << std::endl;
the only down size is you will have to initialize the string outside the class definition because it is a non-integral type, and that you will need a specialization for each type you wish to support (which would probably not be much)

just an idea

proxy
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:Template parameter types as string

Post by Solar »

You are doing strange stuff with templates... :o

I smell some kind of monumental misconception here, but I can't even begin to imagine why you would want to do stuff like that, Candy.

I know you presented your idea of "typecast streams" in this forum once before, but would you mind explaining it again, so I might understand from which direction you're coming at this? It feels like you're doing some awfully complex mojo to solve a problem that isn't there...
Every good solution is obvious once you've found it.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:Template parameter types as string

Post by Candy »

Solar wrote: You are doing strange stuff with templates... :o

I smell some kind of monumental misconception here, but I can't even begin to imagine why you would want to do stuff like that, Candy.

I know you presented your idea of "typecast streams" in this forum once before, but would you mind explaining it again, so I might understand from which direction you're coming at this? It feels like you're doing some awfully complex mojo to solve a problem that isn't there...
The mojo isn't that complex actually, and the problem is that I'd like it all to fit in the C++ type-safe sugar nicely. That is, with the least amount of void *'s in the user code.


My solution for the typecast streams is stream<type> and filter<type1, type2>. Each filter has an attach method, so you can so filter1.attach(filter2);.

All normal old-style interfacing is replaced with new-style interfacing.

You thus have a aos::istream<char> stdin; aos::ostream<char> stdout, stderr; and instead of main(int argc, char **argv) you get a main(vector<string> args). Parsing those arguments is standardized so they all have the same logic behind their parsing (if I can help it that is).

A few tutorials on "making a basic AOS program" will be made, showing how these all fit into normal day life.

In short, it still comes down to these examples:

Code: Select all

// for our basic mp3 player that wants to play mp3s
int main(vector<string> args) {
    filter<aos::file::audio, aos::internal::audio> *mp3player = getModule<aos::file::audio, aos::internal::audio>("mp3", "");
    bool done = false;

    while (!done) {
        int x = rand() % args.size();
        mp3player.put(new stream<aos::file::audio>(args[x]));
        if (some_method_of_signal_received) done=true;
    }
}
allowing everybody who wants to to expand this part of it to create an mp3 player (allowing plain any interface to do anything, and allowing free development and interchange of interfaces. You will NOT be forced to use a new interface for opening new PDF files or other audio files). You can then change it to a general audio player too. This is shown using:

Code: Select all

// for our basic music player that plays any type of file that the system knows. Note, they can be added even after this program is compiled and even while it's running.
int main(vector<string> args) {
    bool done = false;

    while (!done) {
        int x = rand() % args.size();
        string ft = getFiletype(args[x]);

        filter<aos::file::audio, aos::internal::audio> *musicplayer = getModule<aos::file::audio, aos::internal::audio>(ft, "");
        
        musicplayer.put(new stream<aos::file::audio>(args[x]));
        if (some_method_of_signal_received) done=true;
    }
}
Allowing that too with most other types was the first intent.

The global idea in short is being able to use any type without learning another arcane interface and allowing anybody to use all stream types, file types and filters available on the computer without every program writing them again from scratch, hence reducing bugs, enhancing computer speed (everybody can benefit from one optimized version) and making most, if not all, programs future-proof as they should be able to use the file types and invented filters of the future as well as those from the past, without recompiling.
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:Template parameter types as string

Post by Solar »

Candy wrote: You thus have a aos::istream<char> stdin; aos::ostream<char> stdout, stderr; and instead of main(int argc, char **argv) you get a main(vector<string> args).
Be aware that the parameters of main() are part of the standard. You can, of course, add something like the WinAppMain() wrapper to your runtime environment...

Unfortunately, the rest of your post refers mainly to the user-space part of your design. (Which I won't comment on; as a long-time C++ coder I have some gripes with it but that ain't the topic here.)

But I still don't get where exactly you have to pass a type as string, and why you can't get around it in "cleaner" style. Do I understand correctly that you want to pass the type names to a kernel syscall? (Why? Wouldn't a user-space stream server be better?)

Couldn't you use "StreamObjects" instead of plain datatypes, and use member variables / inheritance to solve the identification problem? (Any information on an object should come from the object itself, and StreamObjects could be made to carry information on their type within them.)

Or am I still missing something?
Every good solution is obvious once you've found it.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:Template parameter types as string

Post by Candy »

Solar wrote: Be aware that the parameters of main() are part of the standard. You can, of course, add something like the WinAppMain() wrapper to your runtime environment...
You can overload main, and create a crt0 stub that tries the C++ my-type main first, then the C++ default main and only after that the C main.
Unfortunately, the rest of your post refers mainly to the user-space part of your design. (Which I won't comment on; as a long-time C++ coder I have some gripes with it but that ain't the topic here.)

But I still don't get where exactly you have to pass a type as string, and why you can't get around it in "cleaner" style. Do I understand correctly that you want to pass the type names to a kernel syscall? (Why? Wouldn't a user-space stream server be better?)
Even if you do so as a user-level object, it's a /template/. They are COMPILED IN and can thus never be changed again. There is no practical way to replace them with later-developed stuff.

However.

By using a way to bypass the templates-are-compiled-in doctrine, you can use later-compiled templates as if they were compiled in. This is the exact way to do it, you cannot use templates and you still need to know what the type of the template is, so you explicitly request that as a string. You CAN NOT do that without the typeid or by using inheritance or anything. The storing, loading etc. is a breeze then.



I think the part you're missing is the time part. In normal compilation templates work nicely because everything is present and can be linked in without a problem. However, this is the situation:

Developer one develops a program with any type of audio file. He cannot link against your to-be developed FLAC library since you haven't already developed it and he obviously doesn't have it. He thus links against a blank type of audio filter without knowing what's behind it.

He codes an Ogg Vorbis decoder module, that needs to store what it does in a form that's not compile-time, as in, plain text. The type this would declare is probably (in GCC 3.3.4 syntax with typeid) PN3aos4file5audioE:ogg to N3aos6streamE: . This is equivalent in normal syntax with filter<aos::file::audio *, aos::stream>("ogg", ""). By storing this the module loader can compare the request (for this module) with the actual module at runtime, instead of at compile time. The external links are only created at loading the module, which means that even while your mp3 player runs you can add Ogg support to it. It can (if programmed properly) detect this automatically and allow you to instantly add Ogg files.

You develop, at the same time but on the other side of the world, an AAC module. It conforms to the default format, so it converts from PN3aos4file5audioE:aac to N3aos6streamE:.

The music player program writer was smart and asked the module system for all inputs with a module path to N3aos6streamE: (with audio qualifier, but I don't know how to mangle that in yet). This delivers, after installing just your OS-level AAC plugin, the capability for the music player to load aac files, and it thus asks the system for all filetypes it can play using those modules.

In other words, the most used programs at this time will be freshman programs in a few years, and a full computer game engine should take about a day, given the modules you need (that includes rendering etc.). Also, you develop a separate interface, modules and system modules, which is something I've been aiming for quite a while. One does the interface design and basic code behind it (if necessary with a little help from a programmer), any number create the required modules without strict linking to the other, everybody has a clear interface and you can use all prior art without a hitch. It also eases creating addons to games, new interfaces for music players etc. so these categories finally get free play between media players in terms of the user interface alone, not linked with the formats. It could all be tested with previous formats with less features.

The reason for this export is that I have to be able to store and load the description of the module in template form. I must therefore know what the template is in written form in the source.
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:Template parameter types as string

Post by Solar »

My head is spinning. What you're picturing is a component model, and templates are about the last way to implement it!

Sorry but I can't wrap my mind around the concept of (ab?)using the template mechanism to implement run-time flexibility...
Every good solution is obvious once you've found it.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:Template parameter types as string

Post by Candy »

Solar wrote: My head is spinning. What you're picturing is a component model, and templates are about the last way to implement it!

Sorry but I can't wrap my mind around the concept of (ab?)using the template mechanism to implement run-time flexibility...
I'm kind of abusing the templates for type-safety.

OK, that might have been a more nuanced reply.


My design logic focused around the filter-type as being suitable for all sorts of conversions, from an image to a file, soundinput to soundoutput with echo, mpeg to video, objects in a game to a savegame, a single file to a number of file streams, stuff like that. Making a general filter class would involve passing around numerous void * type objects, because they are from a different type.

I thought then, what if you first design how you want to use it? In c++ you get type-adjustability using templates. The filter-idea is in itself type-independent (as in, you can always use the filter-logic) but it needs to be adjusted for each type you put in and put out. The logic for templates is there.

Now, these templates aren't functional in themselves. They need the actual code for a given transformation, which would in every case be explicitly specified. If none existed for a given requested transformation, the program should be able to tell and give an error, not crash with a link error. Most of all, they had to be able to load them later on, which ruled out the option for templates completely.


this ended me up in the situation where templates would be the best solution, and an impossible one at that. The solution would be making explicit instances of the general filter class. These could then be used for the conversion, be constructed for this operation, given parameters in a similarly type-independent method (have got php-style right now) and be linked in later on. To do so, all template stuff had to both be present, but complete (as in, the link should succeed), and the other half of the code should be able to provide the necessary template (as in, know what to link in later on).

So, the template logic should be passable across the file layer, without causing link errors to the origin end. The idea was to determine the template type in a form of string and pass that to a non-template function in a library, which can then determine what to load. It loads it, constructs (using a placement constructor on already allocated memory since it's not really knowing what the type is) an object and passes it back. It also increases the usage count for the library by one, for purposes of nonused library freeing. Also, it is used for runtime upgrading the library, if you can determine when it's no longer being used you can phase it out gradually. The user code only sees templates, the developer code (for the module) also only sees templates (it inherits from a template class) and the final code casts them to void * after determining their actual type. Result is that the final code can link both halves together without using compile-time constructs.

That is why I use templates.


Small addon, let's close this topic (logically). It's served its purpose.
Post Reply