a good example why it is a pity that sizeof() is not overloadable?!

Discussion in 'C++' started by Christof Warlich, Oct 14, 2005.

  1. Hi,

    I'm trying to build an _efficient_, _purely_ _abstract_ API for inter
    process(or) communication, _completely_ hiding any implementation
    details. The core components are "Buffer", "Address" and "Process".
    They may be instantiated by a "Factory". Here is a simplified, but
    compilable version:

    // Abstract Interface
    enum OsSelector {
    POSIX,
    WIN32
    };

    class Buffer {
    public:
    virtual void *payload(void) const = 0;
    virtual void release(void) = 0;
    };

    struct Address;
    extern const unsigned int addressSize;

    class Process {
    public:
    virtual Address *address(void) = 0;
    virtual void release(void) = 0;
    };
    class Callback {
    public:
    virtual void receive(Buffer *buffer) = 0;
    Process *process;
    };

    class Factory {
    public:
    static Factory *create(OsSelector osSelector = POSIX);
    virtual Buffer *buffer(unsigned int size,
    void *data = 0) = 0;
    virtual Process *process(const char *processName,
    Callback *callback,
    int prio = 0,
    unsigned int stackSize = 0xffff) = 0;
    virtual Address *lookup(const char *processName,
    const char *processorName = 0) = 0;
    virtual void send(Address *address, Buffer *buffer) = 0;
    };

    A simple application, sending a message to another "Process",
    may look like this:

    // Application
    #include <string.h>
    struct Data {
    unsigned int data1;
    unsigned int data2;
    };

    class TaskCallback: public Callback {
    void receive(Buffer *buffer) {
    this->process->release();
    }
    };

    int main(void) {
    TaskCallback taskCallback;
    Factory *factory = Factory::create(POSIX);
    Process *process = factory->process("process", &taskCallback);
    Buffer *buffer = factory->buffer(addressSize + sizeof(Data));
    char *sender = (char *) buffer->payload();
    Data *data = (Data *) (sender + addressSize);
    memcpy(sender, process->address(), addressSize);
    data->data1 = 1;
    data->data2 = 2;
    factory->send(process->address(), buffer);
    }

    While this interface fulfills the outlined needs, it is somewhat
    cumbersome to use when "Address"es should be sent to another
    "Process" intermixed with other data: Typically, one would like to
    define a structure containing the "Address"es and the other data
    members to easily fill the payload of the "Buffer" to be sent. But
    since "Address" is an incomplete type, this is not possible. Instead,
    filling "Address"es into the payload requires employing pointer
    arithmetic, using the variable "addressSize" provided by the interface.

    Finally coming to my point: I know that there are good reasons why
    the "sizeof()" operator cannot be overloaded, most notably because
    the sizes of structure members must be known at compile time already.
    But having seen many discussions that simply state that one can not
    even imagine only _one_ example where it would be nice to overload
    sizeof(), could you agree that here, it would be perfect if one
    could replace the incomplete type "Address" by something like:

    class Address {
    public:
    virtual size_t operator sizeof() = 0;
    };

    Assuming that types may then be created at runtime, it
    would be possible to use the comfort of a structure even when
    "Address"es are involved, provided that the implementation of
    the overloaded sizeof() operator returns the size of the implementation
    for "Address".

    As I don't expect that sizeof() will become overloadable soon
    just because I wish it could be ;-), does anyone know a more elegant
    approach than my pointer arithmetics to fill "Buffer"s with huge
    amount of ordinary data intermixed with the abstract "Address"es?
    Restricting the presence of "Address"es to fixed locations in the
    payload is not an option as the processor the SW is running on is
    part of a network with legacy code that makes extensive use of
    sending (fixed size) addresses.

    Many thanks for the patience to read until this point, and even more
    thanks for any good idea!

    Regards,

    Christof
     
    Christof Warlich, Oct 14, 2005
    #1
    1. Advertising

  2. Christof Warlich

    Dan Cernat Guest

    Christof Warlich wrote:
    > Hi,
    >
    > I'm trying to build an _efficient_, _purely_ _abstract_ API for inter
    > process(or) communication, _completely_ hiding any implementation
    > details. The core components are "Buffer", "Address" and "Process".
    > They may be instantiated by a "Factory". Here is a simplified, but
    > compilable version:
    >

    [snip]
    I'm sure that you could come with a simpler example.

    >
    > While this interface fulfills the outlined needs, it is somewhat
    > cumbersome to use when "Address"es should be sent to another
    > "Process" intermixed with other data: Typically, one would like to
    > define a structure containing the "Address"es and the other data
    > members to easily fill the payload of the "Buffer" to be sent. But
    > since "Address" is an incomplete type, this is not possible. Instead,
    > filling "Address"es into the payload requires employing pointer
    > arithmetic, using the variable "addressSize" provided by the interface.
    >
    > Finally coming to my point: I know that there are good reasons why
    > the "sizeof()" operator cannot be overloaded, most notably because
    > the sizes of structure members must be known at compile time already.
    > But having seen many discussions that simply state that one can not
    > even imagine only _one_ example where it would be nice to overload
    > sizeof(), could you agree that here, it would be perfect if one
    > could replace the incomplete type "Address" by something like:
    >
    > class Address {
    > public:
    > virtual size_t operator sizeof() = 0;
    > };
    >
    > Assuming that types may then be created at runtime, it
    > would be possible to use the comfort of a structure even when
    > "Address"es are involved, provided that the implementation of
    > the overloaded sizeof() operator returns the size of the implementation
    > for "Address".
    >
    > As I don't expect that sizeof() will become overloadable soon
    > just because I wish it could be ;-), does anyone know a more elegant
    > approach than my pointer arithmetics to fill "Buffer"s with huge
    > amount of ordinary data intermixed with the abstract "Address"es?
    > Restricting the presence of "Address"es to fixed locations in the
    > payload is not an option as the processor the SW is running on is
    > part of a network with legacy code that makes extensive use of
    > sending (fixed size) addresses.
    >
    > Many thanks for the patience to read until this point, and even more
    > thanks for any good idea!
    >
    > Regards,
    >
    > Christof


    class Address
    {
    public:
    virtual size_t SizeOf() = 0;
    };

    class DerivedAddress : public Address
    {
    public:
    virtual size_t SizeOf()
    {
    return sizeof(*this);
    }
    };

    /dan
     
    Dan Cernat, Oct 14, 2005
    #2
    1. Advertising

  3. Christof Warlich

    Default User Guest

    Christof Warlich wrote:


    > Finally coming to my point: I know that there are good reasons why
    > the "sizeof()" operator cannot be overloaded


    Just to be nitpicky, it's the sizeof operator, not sizeof(). The ()'s
    are only necessary when the operand is a type.



    Brian

    --
    Please quote enough of the previous message for context. To do so from
    Google, click "show options" and use the Reply shown in the expanded
    header.
     
    Default User, Oct 14, 2005
    #3
  4. Christof Warlich

    ben Guest

    The beauty of C++ is, if you want an extensible typeof operator, you can
    write your own version (with a different name of course.) For example,
    you can do:

    template <typename T>
    std::size_t size_of(void)
    {
    return sizeof(T);
    }

    template <typename T>
    std::size_t size_of(T t)
    {
    return size_of<T>();
    }


    So if you want that to behave differently for type X, you make a
    specialization, like so:

    template <>
    std::size_t size_of<X>(void)
    {
    return 1024;
    }

    If a lot of that specializations take place, you can use a macro:

    #define TYPE_OF_SPEC(TYPE, SIZE)\
    template<>\
    std::size_t size_of<(_TYPE_)>(void)\
    {return (SIZE);}


    TYPE_OF_SPEC(Y, 2046)
    TYPE_OF_SPEC(Z, 2500)
    // ...

    Ben
     
    ben, Oct 15, 2005
    #4
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. greg
    Replies:
    15
    Views:
    590
    Greg Ewing
    Sep 10, 2004
  2. Greg Ewing
    Replies:
    8
    Views:
    390
    Greg Ewing
    Sep 13, 2004
  3. Mr. SweatyFinger
    Replies:
    2
    Views:
    2,249
    Smokey Grindel
    Dec 2, 2006
  4. mttc
    Replies:
    89
    Views:
    2,981
    John W Kennedy
    Oct 23, 2008
  5. John Carter
    Replies:
    43
    Views:
    474
    Tom Copeland
    Jul 12, 2007
Loading...

Share This Page