|
In AcfDelegate.h , line:25
#define ACF_MAKE_PARAMS1_0(t)
#define ACF_MAKE_PARAMS1_1(t) t##1
#define ACF_MAKE_PARAMS1_2(t) t##1, ##t##2
#define ACF_MAKE_PARAMS1_3(t) t##1, ##t##2, ##t##3
#define ACF_MAKE_PARAMS1_4(t) t##1, ##t##2, ##t##3, ##t##4
#define ACF_MAKE_PARAMS1_5(t) t##1, ##t##2, ##t##3, ##t##4, ##t##5
#define ACF_MAKE_PARAMS1_6(t) t##1, ##t##2, ##t##3, ##t##4, ##t##5, ##t##6
should be corrected to:
#define ACF_MAKE_PARAMS1_0(t)
#define ACF_MAKE_PARAMS1_1(t) t##1
#define ACF_MAKE_PARAMS1_2(t) t##1, t##2
#define ACF_MAKE_PARAMS1_3(t) t##1, t##2, t##3
#define ACF_MAKE_PARAMS1_4(t) t##1, t##2, t##3, t##4
#define ACF_MAKE_PARAMS1_5(t) t##1, t##2, t##3, t##4, t##5
#define ACF_MAKE_PARAMS1_6(t) t##1, t##2, t##3, t##4, t##5, t##6
After this patch the Delegate.cpp can compiled with g++ 4.2.1 and have the same output as with MSVC.
For more recent g++ compiler version (ex: 4.6.x), it may complains you about "Explicit Specialization cannot have a storage class" when it sees the declarations of _HandleInvalidCall() (both primary and specialized) in AcfDelegate.h having a 'static' modifier. Just remove the modifier and things will be fine.
"
|
|
|
|
|
Very useful - does what is says on the tin!
|
|
|
|
|
can the delegator call to different typedef of function?
i mean same delegator that call different function having different number of parameter.
from,
-= aLbert =-
|
|
|
|
|
can't seem to get static delegates to work. is this even possible?
-- modified at 15:21 Tuesday 27th February, 2007
|
|
|
|
|
I tried to compile the source in linux using g++(4.0.2), but got some error,
[zzq01@zhangzq71 Delegate]$ make
g++ -c -o Delegate.o Delegate.cpp
In file included from AcfDelegate.h:81,
from Delegate.cpp:12:
AcfDelegateTemplate.h:37:1: error: pasting "," and "typename" does not give a valid preprocessing token
AcfDelegateTemplate.h:38:1: error: pasting "," and "T" does not give a valid preprocessing token
AcfDelegateTemplate.h:66:1: error: pasting "," and "a" does not give a valid preprocessing token
AcfDelegateTemplate.h:75:1: error: pasting "," and "a" does not give a valid preprocessing token
AcfDelegateTemplate.h:103:1: error: pasting "," and "a" does not give a valid preprocessing token
AcfDelegateTemplate.h:201:1: error: pasting "," and "a" does not give a valid preprocessing token
AcfDelegateTemplate.h:202:1: error: pasting "," and "a" does not give a valid preprocessing token
AcfDelegateTemplate.h:366:1: error: pasting "," and "a" does not give a valid preprocessing token
AcfDelegateTemplate.h:367:1: error: pasting "," and "a" does not give a valid preprocessing token
In file included from AcfDelegate.h:85,
from Delegate.cpp:12:
it seems the preprocessor error, I tried another way,
g++ -E Delegate.cpp > output.cpp
g++ -o output output.cpp
it can successfully create the executable file, and the result of the program is correct. Do you know what is the error when compiling with gcc?
Regards,
ZhangZQ
email:zhangzq71@hotmail.com
|
|
|
|
|
I would find it very handy if the delegate had at least an option to not throw an exception when a delegate that has never been assigned is nonetheless invoked. This would avoid having to check .IsEmpty() each time one wants to signal an event and doesn't know if anyone is subscribed. One could add a dummy subscriber to each delegate but not being able to add a default value in the delegate declaration (as is possible in C#) you would have to add it in the containing class constructor and that would complicate matters unnecessarily.
I've modified operator() for my personal use in the way listed below.
Thanks for a great library.
Flavio.
#define ALLOW_EXECUTE_EMPTY
#ifdef ALLOW_EXECUTE_EMPTY
R OnEmptyDelegate() const
{
return R();
}
#else
R OnEmptyDelegate() const
{
throw InvalidOperationException();
}
#endif
R operator()(ACF_DELEGATE_FUNCTION_PARAMS) const
{
if (this->_last == NULL)
OnEmptyDelegate();
if (this->_last->Previous != NULL)
InvokeDelegateList(this->_last->Previous ACF_DELEGATE_COMMA ACF_DELEGATE_FUNCTION_ARGS);
return this->_last->Invoke(ACF_DELEGATE_FUNCTION_ARGS);
}
|
|
|
|
|
Thanks Flavio, the exception behavior is changed in the new version - when an empty delegate is called and the return type is void, no exception will be thrown.
Yingle
|
|
|
|
|
1. Your implementation is probably appropriate for most applications (especially GUI) although I doubt that class templates that use function signatures as template arguments can be 'Easy to understand and use'.
2. compiling your code with g++ 3.4 gives the following errors:
<small><br />
Compiling source file(s)...<br />
Delegate.cpp<br />
In file included from AcfDelegate.h:74,<br />
from Delegate.cpp:12:<br />
AcfDelegateTemplate.h:37:1: pasting "," and "class" does not give a valid preprocessing token<br />
AcfDelegateTemplate.h:38:1: pasting "," and "T" does not give a valid preprocessing token<br />
AcfDelegateTemplate.h:66:1: pasting "," and "a" does not give a valid preprocessing token<br />
AcfDelegateTemplate.h:75:1: pasting "," and "a" does not give a valid preprocessing token<br />
AcfDelegateTemplate.h:103:1: pasting "," and "a" does not give a valid preprocessing token<br />
AcfDelegateTemplate.h:201:1: pasting "," and "a" does not give a valid preprocessing token<br />
AcfDelegateTemplate.h:202:1: pasting "," and "a" does not give a valid preprocessing token<br />
AcfDelegateTemplate.h:366:1: pasting "," and "a" does not give a valid preprocessing token<br />
AcfDelegateTemplate.h:367:1: pasting "," and "a" does not give a valid preprocessing token<br />
<br />
... and many more<br />
</small>
Your macros don't work as expected for g++ (don't know whether it's a g++ bug). The macro cascades can easily be avoided by using a simple Code Generator that does what the current macros are supposed to do.
It would be nice if you compared your implementation with other implementations (advantages/disadvantages, performance, ease of use, ...).
Best wishes,
Roland Pibinger
|
|
|
|
|
Hi, Roland
Thanks for your comments. Here are my answers:
1. It's impossible to have a better syntax in current C++. The original syntax is Delegate0<R>, Delegate1<R, T1>, Delegate2<R, T1, T2>, .... However many people do not like it. The function signature is probably the best we can do (at least it has a clear separation of return value and parameters).
2. I did not try g++ 3.4, but on g++ 3.2.3 they are just warnings. Maybe you can avoid this by some compiler switch (not sure). I will look at this when I have time. (If you have better solution, don't hestitate to tell me)
3. People really asked about comparsion to other delegate implementations (boost.signal, or others delegate classes on CodeProject). It's a good topic, I will try when I update this article later.
Ying Le Jia
|
|
|
|
|
Hi, Yingle!
Yingle Jia wrote:
2. I did not try g++ 3.4, but on g++ 3.2.3 they are just warnings. Maybe you can avoid this by some compiler switch (not sure). I will look at this when I have time. (If you have better solution, don't hestitate to tell me)
I don't know if it's a better solution but you could preprocess only the file with VC++, e.g.
cl /EP Delegate.cpp > out.txt
and then exchange the contents of AcfDelegate.h with the relevant portion of the preprocessor output (replace the macros with source code).
Best wishes,
Roland Pibinger
-- modified at 13:42 Tuesday 6th September, 2005
|
|
|
|
|
Yingle Jia wrote: 1. It's impossible to have a better syntax in current C++. The original syntax is Delegate0<r>, Delegate1<r, t1="">, Delegate2<r, t1,="" t2="">, .... However many people do not like it. The function signature is probably the best we can do (at least it has a clear separation of return value and parameters).
Just realize that some compilers don't support this syntax (this is why Boost and other implementations for TR1 of STL offer 2 versions of the fuction template).
Yingle Jia wrote: 3. People really asked about comparsion to other delegate implementations (boost.signal, or others delegate classes on CodeProject). It's a good topic, I will try when I update this article later.
Boost is a good one to compare your implementation to since there is a strong liklihood that much of the work done by Boost will end up in the next version of the Standard C++ Libraries. If your implementation is more efficient and/or robust, you may want to tweak it a bit (to meet their coding standards) and submit it for review.
If you decide to become a software engineer, you are signing up to have a 1/2" piece of silicon tell you exactly how stupid you really are for 8 hours a day, 5 days a week
Zac
|
|
|
|
|
Hi, Zac
Thanks for your comments. Boost does have good signal and function libraries, and I learned something from them (e.g. the function signature syntax). However, my Delegate class has different design goals, e.g. I like it to be like C#/.NET and I don't like to mass the design (syntax) for old and silly compilers (like VC6). People can have their own choices.
Yingle
|
|
|
|
|
I wouldn't call VC6 "old and silly". There are still plenty of companies that use it as their standard development environment (the company I work for is one of them ... and quite frankly, management has no immediate plans to upgrade ... unfortunately).
My points with regard to boost is simple: 1) many of the libraries in TR1 are boost derivitives and signals could very well make that list and 2) it is designed to be portable. If you know that there is a strong chance something will become a standard, it is worth your time to at least learn how to use it. If portability is not a concern (that is, you know for sure that you won't be switching compilers, ever), then you have nothing to worry about. I don't know many companies that can guarantee that, though. Just some things to keep in mind.
As a side note, creating libraries like this are excellent academic exercises and can only enhance your skills (and you did a pretty good job -- the exception-safe syncronization is great).
If you decide to become a software engineer, you are signing up to have a 1/2" piece of silicon tell you exactly how stupid you really are for 8 hours a day, 5 days a week
Zac
|
|
|
|
|
Zac,
I quite understand your points. Yes, VC6 is still widely used (some people don't want to upgrade to VC7/7.1 because UI changed a lot, some people don't want to upgrade because they mistakenly think VC7/7.1 can only be used to write .NET programs). Actually when I first wrote the class, it supported the syntax Delegate0<r>, Delegate1<r, t="">, Delegate2<r, t1,="" t2=""> ... like boost, which is portable and supports VC6. However, when I talked to people, many of them (I guess they are using VC7/7.1 or GCC like me ^_^) thought that syntax is ugly, and a big concern is that people will use that syntax everywhere in order to make their code "portable" (I see many people using boost.function are using function0<r>, function1<r, t=""> everywhere instead of the prefered syntax). That's why I did not put VC6 in my must-support list. Of course this can change according to user feedback.
Yingle
|
|
|
|
|
I'm VERY interested in the way this class makes use of variable template paramters. I have never before seen this (T1, T2, ..., TN) syntax. It's only available in VC7.1+, and very few UNIX C++ compilers. I notice BOOST makes use of it as well, but also has the old-fashioned Functor1 Functor2 Functor3 style syntax for backwards compilers.
Does anyone have a link that describes this syntax in detail? I've been unlucky so far with Google.
-- modified at 12:46 Thursday 1st September, 2005
One more question - Why does the article say it only supports functions with up to 6 parameters? Does that ...TN syntax only support 6 paramters?
|
|
|
|
|
armentage,
Currently there is no direct variable template parameters support in standard C++ (though there is a proposal for C++0x). One has to use template (partial) specialization to achieve it. i.e.
template <class TSignature>
class Delegate; // no body
template <class R>
class Delegate<R ()> {
};
template <class R, class T1>
class Delegate<R (T1)> {
};
template <class R, class T1, class T2>
class Delegate<R (T1, T2)> {
};
template <class R, class T1, class T2, class T3>
class Delegate<R (T1, T2, T3)> {
};
...
You see there is a compiler-time limit on the numbers of template parameters. Boost actually supports generating arbitary numbers using script language, but I think it's a good practice to keep function parameters no more than 6 - that's the reason.
|
|
|
|
|
What I don't understand is how those (T1,T2,T3) work. Was that just pseudo code in your example? I've never seen any C++ like that other than your Delegate and the Boost signals library.
|
|
|
|
|
armentage wrote: Currently there is no direct variable template parameters support in standard C++ (though there is a proposal for C++0x). One has to use template (partial) specialization to achieve it. i.e.
...
You see there is a compiler-time limit on the numbers of template parameters. Boost actually supports generating arbitary numbers using script language, but I think it's a good practice to keep function parameters no more than 6 - that's the reason.
This is partially correct. Standard C++ currently does support variable template parameters, but there are several compilers that do not fully support it. Additionally, even those that do, some of them do not support the function-style syntax (even though it is technically standard as well). The C++0x Standard is suppose to more formally define this area, but you can get compilers that are fully compliant in this area.
armentage wrote: What I don't understand is how those (T1,T2,T3) work. Was that just pseudo code in your example? I've never seen any C++ like that other than your Delegate and the Boost signals library.
It is real code, however, it is not supported by all compilers. If you take away the (), it is more portable at the moment. Boost has several libraries that use this feature (the function template is another example). You should note that currently, the Boost libraries offer 2 versions to support non-compliant compilers. I imagine that will change when C++0x is finalized.
If you decide to become a software engineer, you are signing up to have a 1/2" piece of silicon tell you exactly how stupid you really are for 8 hours a day, 5 days a week
Zac
|
|
|
|
|
|
yeah. from me as well
|
|
|
|
|
|
I have not tried it yet, but my personal opinion on Boost is that it is designed for advanced C++ developers.
|
|
|
|
|
Hi Yingle, got my 5, i'm really impressed by your ACF.
actually, boost::signal dose almost the same thing as you described here.
IMHO, boost is designed by advanced c++ developers for all standard c++ users.
|
|
|
|
|
It takes only a short while to understand boost, be the best while work with the best, no worry!
|
|
|
|
|
I am not sure about this. I find many parts of the boost documentation very hard to understand. I admit I have not read it recently, maybe things are better now.
John
|
|
|
|
|