Conceptual function type problem

C

cppnow

Hello. I have a strange conceptual problem I'm trying to think about.

I would like to build a library that allows the user to do the
following:

1) User defined types:
The user defines their own types as needed for their particular
application and registers them with the library.

class ClassA {};
class ClassB : public ClassA {};
class ClassC: public ClassB{};

REGISTERTYPE(ClassA);
REGISTERTYPE(ClassB);
REGISTERTYPE(ClassC);

2) User defined functions:
The user defines a set of functions as needed for their particular
application and registers them with the library.

ClassA Function1(ClassB);
ClassB Function2(ClassB);
ClassC Function3(ClassC, ClassB);
ClassC Function4(ClassC);

REGISTERFUNCTION(Function1);
REGISTERFUNCTION(Function2);
REGISTERFUNCTION(Function3);
REGISTERFUNCTION(Function4);

3) The user can then query the library for functions that return the
type it requires and call those functions and get an object of the
desired type OR a type that can be implicitly converted to the desired
type:

// User needs a ClassA object
vector<ClassA> results;
vector<something?> functions = GetFunctions(some way to indicate
ClassA);
// GetFunctions should return [pointers/function objs/something else?]
for Functions 1, 2, 3 and 4
// (since a ClassA object can be obtained from them or implicitly
converted from their return types)
for(functions::const_itr itr = functions.begin(); itr !=
functions.end(); itr++)
results.push_back(CALLFUNCTION(itr));

I'm trying to develop an architecture that would permit this... I'm
thinking the registration functions would need some kind of template
metaprogramming code... could this maybe be done simply with
polymorphism and virtual functions? Boost::any was another idea I
considered.

I think I am getting stuck in two areas: trying to query for the
return type of a function and then trying to determine if that return
type can be implicitly converted to some other type (either because
the return type is a derived class of the desired type or because the
return type has an implicit conversion operator to the desired type).

Any info appreciated. Obviously not looking for code, more just tips
on how to think about this kind of a problem.

Cheers
 
F

Frank Birbacher

Hi!

3) The user can then query the library for functions that return the
type it requires and call those functions and get an object of the
desired type OR a type that can be implicitly converted to the desired
type:

So how about parameters to these functions? How is the user supposed to
call the functions if she doesn't know what arguments to provide?

It seems to me you try to "register" ways (functions) which can later be
used to create certain objects. Am I right here?

Frank
 
B

Barry

I think I am getting stuck in two areas: trying to query for the
return type of a function and then trying to determine if that return
type can be implicitly converted to some other type (either because

have you try Boost.Function,
but it can't trait out the return type of operator function
 
C

cppnow

Thanks for the tips.

Part of the challenge I'm having is figuring out conceptually how to
store these objects.

I.e. I could have a vector<boost::function>, but then i have the issue
that these functions take all kinds of parameters and return whatever
types they want (as determined by the user who wrote them).

I can't use templates for this reason as well.

With regards to parameters, i need a way to basically query the
function at run time and determine what types it takes as parameters
and then lookup a function in the function library that returns the
appropriate type. I.e. the system says I need to execute Function1,
but to do so i need an object of ClassB, so let's go through all the
functions and find the ones that return an object of ClassB (Function2
in the previous example would meet this requirement) and execute that
function, take its return value and pass it to Function1.

I'm leaning towards template metaprogramming as a way to automatically
generate all possible combinations of types with the appropriate
dynamic_casts in there to handle inherited types, but I'm quite the
newb on MPL.

Pointers appreciated
 
B

BobR

cppnow said:
Thanks for the tips.

Thanks for top-posting.
Part of the challenge I'm having is figuring out conceptually how to
store these objects.

What objects?

Why not just let your users program it in C++, directly?
It sounds to me like you are trying to re-invent scripting language.
( there are already thousands of those!! )
[ sorry said:
I.e. I could have a vector<boost::function>, but then i have the issue
that these functions take all kinds of parameters and return whatever
types they want (as determined by the user who wrote them).

Look up 'Multiple dispatching' (using the Visitor pattern).

There is a (somewhat) simple example in "Thinking in C++" Vol. 2.
Chapter 10: Design Patterns, section 'Multiple dispatching'.

Get "Thinking in C++", 2nd ed. Volume 1&2 by Bruce Eckel
(available for free here. You can buy it in hardcopy too.):
http://www.mindview.net/Books/TICPP/ThinkingInCPP2e.html


FAQ http://www.parashift.com/c++-faq-lite
 
C

cppnow

Part of the challenge I'm having is figuring out conceptually how to
store these objects.

What objects?

Why not just let your users program it in C++, directly?
It sounds to me like you are trying to re-invent scripting language.
( there are already thousands of those!! )
[ sorry, just being a smart-ass. <G> ]

You've kind of hit the nail on the head here. The idea is that the
user provides the building blocks of the program (functions and data
types) and the library can reconfigure them as needed at run-time and
'execute' these new reconfigured 'programs'. So for example if the
user supplied two ways (functions) of creating an object (of a user-
defined type), the library might pick one at one point and another at
another point. You can think of these reconfigured 'programs' as
deferred-evaluation expressions. The user doesn't actually build the
'program' except by specifying what he wants to pop out of the
'program' and the library assembles the building blocks necessary to
produce it

Look up 'Multiple dispatching' (using the Visitor pattern).

There is a (somewhat) simple example in "Thinking in C++" Vol. 2.
Chapter 10: Design Patterns, section 'Multiple dispatching'.

Get "Thinking in C++", 2nd ed. Volume 1&2 by Bruce Eckel
(available for free here. You can buy it in hardcopy too.):
http://www.mindview.net/Books/TICPP/ThinkingInCPP2e.html

I had a look at both. My hunch with multiple dispatching using visitor
is passing an operator object at a data object and using the double
calls to resolve against the types of both. This would mean that the
user would have to provide a version of each operator for every type
in his program. I'm more hoping the user could say "This operator
requires an object of type B, any object of a type derived from B or
any object convertible to type B" and the library would understand how
to work within the user's type-hierarchy to satisfy these
requirements.

As a more involved example, the user might provide the library with
the following types and functions:

class Q;
class A { public: A(const &Q) {// construct from a Q} };
class B : public A {};
class C { public: operator A() {// convert this C object to an A
object} };

int Builder1(const A& b); // do something with the A
B Builder2(); // the library should know that it can use this function
to build the parameter to be fed into Builder1 (since all Bs are As)
C Builder3(); // likewise with this function since all Cs can be
converted to As
Q Builder4(); // and again with this function since As can be
constructed using Qs

The user can then ask the library to use these building blocks to
produce an int. The only way to do that is with Builder1(), which
takes as input the output of one of the other builders, etc... Being
able to automatically make these determinations is the work of the
library. The library wouldn't actually build C++ expressions, but it
might pass around function objects, move data in boost::any objects,
use dynamic_cast<> to handle traversing the type hierarchy, test for
convertibility using boost::is_convertible, etc., etc.

Since this line of reasoning uses compile-time information (types,
conversions, return values, etc.), I'm thinking this is a natural
application of metaprogramming, but i don't want to start a huge
effort in that direction if there's something fundamental I'm missing.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,981
Messages
2,570,187
Members
46,730
Latest member
AudryNolan

Latest Threads

Top