The problem might make sense with a simpler example. Try identifying the problem here: template struct id { typedef T type; }; template void foo(typename id::type x); foo(5); // error The problem is that the compiler cannot deduce what T should be; it's not directly used anywhere. You'd have to explicitly provide it: foo(5) or let it deduce it in some other way: template void foo(typename id::type x, T y); foo(5, 7); // okay, T is int because 7 is int This makes sense: how could the compiler figure out which T s, supplied to id result in id::type matching?
There could be specializations, and the entire thing would be costly anyway, if possible Likewise, there's nothing the compiler has available to deduce R and Args Instead, you should do this: template typename CallbackBase::CallbackBasePtr MakeCallback( R cb(Args...) ) { typename CallbackBase::CallbackBasePtr p( new FunctionCallback( cb )); return p; } Finally, you have other minor issues that need fixing which Xeo has outlined.
The problem might make sense with a simpler example. Try identifying the problem here: template struct id { typedef T type; }; template void foo(typename id::type x); foo(5); // error The problem is that the compiler cannot deduce what T should be; it's not directly used anywhere. You'd have to explicitly provide it: foo(5), or let it deduce it in some other way: template void foo(typename id::type x, T y); foo(5, 7); // okay, T is int because 7 is int This makes sense: how could the compiler figure out which T's, supplied to id, result in id::type matching?
There could be specializations, and the entire thing would be costly anyway, if possible. Likewise, there's nothing the compiler has available to deduce R and Args. Instead, you should do this: template typename CallbackBase::CallbackBasePtr MakeCallback( R cb(Args...) ) { typename CallbackBase::CallbackBasePtr p( new FunctionCallback( cb )); return p; } Finally, you have other minor issues that need fixing, which Xeo has outlined.
2 Should be with typename and R (*cb)(Args...). :) – Xeo Apr 13 at 23:16 1 @Xeo: Yes on the typename, thanks. But either syntax is fine for functions, similar to how int I becomes int* i.
I find not putting those three characters is clearer. – GMan Apr 13 at 23:18 2 Ah, right.. forgot the automatic conversion of functions to pointer-to-functions, you're right. But there's still a problem with that code, the return type should be CallbackPtr not CallbackBasePtr, as that typedef doesn't exist (which was part of the actual problem, as SFINAE kicked in and took that function out of the overload set).
– Xeo Apr 13 at 23:20 1 @VJo: GMan is right, the args is non-deducible. The main reason is the ::. The :: behavior like a "deducing-firewall", type deducing can not pass through it.
– yoco Apr 13 at 17:59 1 @VJo: I can only recommend this video to you, it explains SFINAE quite nicely and tells you, why the argument is non-deducible. In general, I can recommend the whole series. – Xeo Apr 13 at 7:47.
To recollect what I mentioned in the comments of the other answers: First, as @GMan says, your argument of MakeCallback was non-deducible. Second, your return type of MakeCallback was wrong. It should be CallbackPtr, as a CallbackBasePtr typedef doesn't exist.
This lead to SFINAE kicking in and not considering your function as a possible function to call even when the argument was fixed. Third, your FunctionCallback constructor wanted a funccb* pointer, while funccb already is a (function-)pointer, so you would have to pass a pointer-to-function-pointer, eg. New FunctionCallback(&cb).
Second and third, I understand (stupid copy&paste), but can you elaborate a bit more on the first. Why is the argument not deducible? The type should be the same, no?
– VJo Apr 14 at 7:28.
It's better to use than to reinvent it… It's also better to copy directly from your compiler's implementation. Generally, using fewer template parameters is a good thing, too. But, it's always tempting to solve these problems… so, knowing what I do, but not looking directly at that right now, here is how I'd handle it.
The code to simply Call a functor will not be specialized for the different kinds of functors, so it should be in the general template case. To make minor adjustments to the general template, a traits class serves best. Template struct callback_traits { typedef F const &local_type; // fallback case: only keep a reference }; template struct callback_traits::value >::type > { typedef F local_type; // better to keep a copy as this is a callback }; template struct Callback { typedef typename callback_traits::local_type local_type; local_type fn; Callback( local_type const &fn_in ) : fn( fn_in ) {} template typename std::result_of::type Call( Args ... a ) { return fn( a ... ); } }.
Added a missing (I think) type after result_of, not so sure of myself, so I would appreciate if you cross-checked. – Matthieu M. Apr 14 at 6:22 @Matthieu: Yes, thanks!
I didn't test at all before, but with that fix it works: ideone. Com/KkX9C - I also added support for calling printf. – Potatoswatter Apr 14 at 7:22 I know I could have used functional, but I wanted to see what's all hype about variadic templates :) By the way, I like your solution, but how would you extend it for pointer to member method, and pointer to constant member method?
– VJo Apr 14 at 7:31 @VJo: Well, in functional they have a lot of separate specializations… see update, I refactored this to differentiate the key cases so the legwork should be reduced. New demo: ideone. Com/IQghG – Potatoswatter Apr 14 at 8:03.
Fixed some type-o's and specialized MakeCallback to accept function pointers. As GMan said, your template arguments to MakeCallback are in a non-deducible context. #include template class CallbackBase { public: typedef std::shared_ptr > CallbackPtr; virtual ~CallbackBase() { } virtual R Call( Args ... args) = 0; }; template class FunctionCallback : public CallbackBase { public: typedef R (*funccb)(Args...); FunctionCallback( funccb cb_ ) : CallbackBase(), cb( cb_ ) { } virtual ~FunctionCallback() { } virtual R Call(Args... args) { return cb( args... ); } private: funccb cb; }; template typename CallbackBase::CallbackPtr MakeCallback( R (*cb)(Args...) ) { typename CallbackBase::CallbackPtr p( new FunctionCallback( cb ) ); return p; } bool Foo_1args( const int & t) { return true; } int main() { auto cbObj = MakeCallback( & Foo_1args ); } Update: The C++ standard defines non-deduced context in 14.8.2.5 temp.deduct.
Type, paragraphs 5 - 6. There is a bulleted list there which I won't claim to fully understand. The marker for me is: Any time you see "::" after your template parameter, that template parameter is in a non-deduced context, meaning it must be explicitly specified at the call site.
1 Might want to point out what exactly was wrong: FunctionCallback's ctor wanted a funccb * pointer, while funccb is already a pointer, so it demanded a pointer-to-pointer. Second thing was the return type of MakeCallback, it was CallbackBasePtr which obviously doesn't exist, it is CallbackPtr. – Xeo Apr 13 at 23:21 The same question as for GMan : How is the declaration of MakeCallback different from mine?
Mine is using the same typedef. – VJo Apr 14 at 7:26 I've attempted an informal definition of non-deduced context. – Howard .
I use Visual Studio 2010 and auto keyword is fine but the variadic template support is not there yet. Last I knew clang was the only C++ compiler which did support variadic templates at this stage other than beta versions or concepts.
1 gcc 4.5.2 support them, in fact, it's got most of the C++0x features as far as I experimented, apart from the ranged-based for :/ – Matthieu M. Apr 14 at 6:21 You mean compiler? I am using default g++ on ubuntu 10.10 (not sure which exactly version, 4.5.X) – VJo Apr 14 at 6:28 Looks like there is some support but no template aliases in any g++ and I've seen complaints with variadic template bugs even in g++ 4.6 here's a reference to supported features gcc.gnu.
Org/projects/cxx0x. Html – AJG85 Apr 14 at 15:24.
The problem might make sense with a simpler example. The problem is that the compiler cannot deduce what T should be; it's not directly used anywhere. This makes sense: how could the compiler figure out which T's, supplied to id, result in id::type matching?
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.