I want to store boost::function<void(void*)> in order to point to an arbitrary functor class object. I tried the following code, but it does not compile :
struct MyFunctor
{
template<class T>
void operator()(T* a)
{
T& ref = *a;
}
};
struct MyFunctor2
{
template<class T>
void operator()(T* a)
{
T& ref = *a;
}
};
boost::function<void(void*)> anyFunctorPtr;
anyFunctorPtr= MyFunctor();
double a = 5;
anyFunctorPtr(&a);
The compiler error is error C2182: 'ref' : illegal use of type 'void'
boost::function, just like std::function requires a specific functor signature (in your case void(void*)), which is the signature it will try to call your functor with. That's why T is deduced as void and the compiler refuses to give you a void&, rightfully so.
Your example is fundamentally add odds with itself, because if you want to have type erasure, you cannot have templates, as the compiler cannot know which templates to instantiate otherwise. Assume for a moment that boost::function<magic> could do what you want.
If you give the compiler code like this:
void foo(boost::function<magic> func)
{
double a = 5;
func(&a);
}
How would the compiler know whether to generate a T = double instantiation for MyFunctor or MyFunctor2? It simply cannot know, and thus it cannot generate the right code. There is no limit on the amount of templated functor classes you can have and the number of types you can attempt to call operator() with, so instantiating them automatically ahead of time is also out of the question.
Related
I wrote a function template to "convert"/repack a boost::shared_ptr<T> to a std::shared_ptr<T> and vice versa by following this proposal. It's working fine unless I have a boost::shared_pt<T> and the type of T is an abstract class.
What I figured out so far is, that the problem occurs when boost/shared_ptr.hpp and boost/shared_array.hpp are included together. If only boost/shared_ptr.hpp is included it's working when the type of T is an abstract class.
I'm using clang 3.3 and boost 1.55.0 . It would be great if someone could tell my why it's not working and how to get it working.
Thanks for your help
Here is a minimal example:
//main.cpp
#include <boost/shared_array.hpp> //removing this include and it's working
#include <boost/shared_ptr.hpp>
#include <memory>
template<typename SharedPointer> struct Holder {
SharedPointer p;
Holder(const SharedPointer &p) : p(p) {}
Holder(const Holder &other) : p(other.p) {}
Holder(Holder &&other) : p(std::move(other.p)) {}
void operator () (...) const {}
};
template<class T>
std::shared_ptr<T> to_std_ptr(const boost::shared_ptr<T> &p)
{
typedef Holder<std::shared_ptr<T>> H;
if(H *h = boost::get_deleter<H, T>(p)) // get_deleter seems to cause the problem
{
return h->p;
}
else
{
return std::shared_ptr<T>(p.get(), Holder<boost::shared_ptr<T>>(p));
}
}
Here the code I used to test it:
//main.cpp
template<typename T> class Base
{
public:
T value;
virtual void abstract() = 0;
virtual ~Base() {}
};
template<typename T> class Derived : public Base<T>
{
public:
virtual void abstract() override {}
virtual ~Derived() {}
};
int main(int argc, const char * argv[])
{
boost::shared_ptr<Base<int>> ptr{new Derived<int>()};
// error here
std::shared_ptr<Base<int>> a = to_std_ptr(ptr);
// no error here
std::shared_ptr<Base<int>> b = to_std_ptr(boost::static_pointer_cast<Derived<int>>(ptr));
return 0;
}
Here's the error message(shortened):
boost/smart_ptr/shared_array.hpp:111:102: error: array of abstract class type 'Base<int>'
shared_array( shared_array<Y> const & r, typename boost::detail::sp_enable_if_convertible< Y[], T[] >::type = boost::detail::sp_empty() )
main.cpp:64:40: note: in instantiation of template class 'boost::shared_array<Base<int> >' requested here
if(H *h = boost::get_deleter<H, T>(p))
main.cpp:86:36: note: in instantiation of function template specialization 'to_std_ptr<Base<int> >'requested here
std::shared_ptr<Base<int>> i = to_std_ptr(ptr);
main.cpp:23:18: note: unimplemented pure virtual method 'abstract' in 'Base'
virtual void abstract() = 0;
What I get from the error message is that the compiler tried to create an array of abstract classes what of course doesn't work. But why is he even trying to do so and what has boost/sharred_array to do with that. Is he maybe picking the wrong overload for boost::get_deleter?
Here's a small example of where the error comes from:
struct abstract
{
virtual void foo() = 0;
};
template<class X, class Y>
struct templ {};
template<class T>
struct bar
{
template<class U>
bar(templ<U[], T[]>) {} // (A)
};
int main()
{
bar<abstract> x;
}
It seems even to be illegal to form the type array of [abstract-type] in (A), therefore instantiating the class template bar with the argument abstract makes the program ill-formed.
The same thing is happening in the background for shared_array. But why is shared_array<Base> instantiated?
The free function boost::get_deleter is overloaded, shared_array.hpp adds an overload to the overload set (actually, adds a template):
template< class D, class T > D * get_deleter( shared_array<T> const & p );
Before overload resolution, even before finding out which functions are viable, function templates need to be instantiated. Instantiating this get_deleter template above leads to instantiating shared_array<Base>, which leads to the program being ill-formed.
The solution is, not to let the above get instantiated: Don't supply the template parameter T, it can't deduce the T in shared_array<T> from a shared_ptr<T>: the two types are unrelated.
Change
if(H *h = boost::get_deleter<H, T>(p))
to
if(H *h = boost::get_deleter<H>(p))
and it works.
Explanation why letting T be deduced works:
When writing a function call where a function template could be meant (looking at the name called), the template parameters have to be set. You can supply them explicitly (inside <> as in get_deleter<H, T>). If you don't supply all of them explicitly (as in get_deleter<H>), the remaining ones have to be deduced from the arguments of the function call.
After all template parameters have been either set explicitly or deduced, their occurrences in the function template are substituted. The error when using get_deleter<H, Derived> occurs in this step: the substituted get_deleter looks like this:
template<> H * get_deleter( shared_array<Derived> const & p );
Here, shared_array<Derived> needs to be instantiated. But during this instantiation, the error explained above occurs. (Note: it's not in the immediate context of get_deleter, therefore SFINAE doesn't apply.)
Now, when you don't explicitly supply the second template parameter, it has to be deduced. And this deduction fails for the function template
template< class D, class T > D * get_deleter( shared_array<T> const & p );
if you use an argument expression of type shared_ptr<Derived>. As deduction fails, no instantiation takes place of the function template, and therefore no instantiation of shared_array<Derived> (deduction fails = some template parameters could not be set).
Why does deduction fail? The compiler needs to deduce the template parameter T inside the function parameter type shared_array<T> const& from the argument expression, which is of the type shared_ptr<Derived>. But this deduction can only succeed (with few exceptions) when the function parameter type can be made equal to the argument expression type. I.e., it can only succeed if there's some type X, such that shared_array<X> is the same type as shared_ptr<Derived>. But there isn't: the specializations of shared_ptr and shared_array are unrelated.
Therefore, the template parameter T of this get_deleter overload cannot be deduced; therefore this function template isn't instantiated, and shared_array<Derived> isn't instantiated.
Deduction failure is a special kind of failure (like SFINAE): It doesn't lead to the program being ill-formed (i.e. it doesn't lead to a compilation error). Rather, the function template for which deduction didn't succeed simply doesn't add a function to the overload set. If there are other functions in the overload set, one of those can be called instead.
Another function template
template<class D, class T> D * get_deleter( shared_ptr<T> const & p )
from boost/smart_ptr/shared_ptr.hpp runs through the same process. However, deduction succeeds here, and a specialization get_deleter<H, T> (with the H and T from to_std_ptr) is added to the overload set. It'll later be chosen by overload resolution.
I have this function:
template <typename T, void (T::*pf)()>
void call(T& t)
{
(t.*pf)();
}
If I have class foo with a method with the appropriate signature (say bar) I can call it like this call<foo, &foo::bar>(); and it's fine. However if bar is const gcc and msvc are happy to compile it when called like this call<const foo, &foo::bar>(). Clang complains that the second template parameter is invalid. When I put const in the template arguments (void (T::*pf)() const) all tree compile it.
Now, this is not a huge issue, but my code becomes much much cleaner if I don't have to write this wretched const in the template arguments.
So the question basically is: What does the standard say about this? Is this a clang bug or are gcc and msvc just letting it slide because they're cool like that?
PS Here's a link to a complete repro program: http://codepad.org/wDBdGvSN
The const-ness of a method is part of the 'signature' of it. So, the proper way to define and use a pointer to member is:
R (Obj::*)(Args) // for non-const member
R (Obj::*)(Args) const // for const member
Note that a const member can be called on a non-const object, which is not the case with R (const Obj::*)(Args).
A way to solve this is to abstract such function pointers, by defining 'call wrappers':
template<typename O, void (O::* f)()>
struct NonConstFunc
{
static void call(O* o)
{
(o->*f)();
}
};
template<typename O, void (O::* f)() const>
struct ConstFunc
{
static void call(O* o)
{
(o->*f)();
}
};
Then, you can use it the following way (here the abstraction takes place):
template<typename Obj, typename Function>
void call(Obj* o)
{
Function::call(o);
}
There is a live example here.
This is just the main idea. You can extend it with automatic detection of whether the method is const or not, without changing the user code.
I want to do something like the following:
Example(&Class::MemberFunction, this));
//...
template<class T_CLASS>
inline static void Example(void (T_CLASS::*MemberFunctionPointer)(), T_CLASS* InstancePointer)
{
SomeClass<T_CLASS>::Bind<MemberFunctionPointer>(InstancePointer);
}
But I get the error: *template parameter 'T_MEMBER_FUNCTION' : 'MemberFunctionPointer' : a local variable cannot be used as a non-type argument*
Any solutions for this problem? I want to provide an easier way to call "Bind"
Thanks, Mirco
//edit:
I want MemberFunctionPointer to be a non-type template parameter because in "Bind" I again need it as a template argument.
As you wrote in your answers, in my case MemberFunctionPointer is a variable and its value is unknown at compile time. But MemberFunctionPointer always points to the same function. Is there a way to for example make it constant so that the compiler knows it at compile time?
There are two kinds of things template parameters can be: types and compile-time constant expressions. The contents of a function parameter is not a compile-time determinable value. And therefore, the compiler cannot instantiate a template based on it.
Remember: a template is a type. And types must be determinable at compile time.
You probably should pass the member pointer as an argument to the Bind function.
I am not quite sure what you are trying to achieve?
If a MemberFunctionPointer is a variable, that the value of is unknown at compile time and, for example, may depend on some user behaviour - then it cannot be used as a template argument.
If, on the other hand, MemberFunctionPointer can be actually deduced at compile-time, you should pass it as a template argument, instead of a function parameter. Consider the following example:
(use Bind and call in the first case; in the second case, use StaticBind and callStatic)
#include <stdio.h>
class X {
public:
int x;
void foo() {printf("foo\n");}
void bar() {printf("bar\n");}
};
template <typename T>
class SomeClass {
public:
static void Bind(void (T::*MemberFunctionPointer)(), T *obj) {
(obj->*MemberFunctionPointer)();
}
template <void (T::*MemberFunctionPointer)()>
static void StaticBind(T *obj) {
(obj->*MemberFunctionPointer)();
}
};
template <class C>
static inline void call(void (C::*MemberFunctionPointer)(), C *obj) {
SomeClass<C>::Bind(MemberFunctionPointer,obj);
}
template <class C, void (C::*MemberFunctionPointer)()>
static inline void callStatic(C *obj) {
SomeClass<C>::template StaticBind<MemberFunctionPointer>(obj);
}
int main() {
X obj;
call<X>(&X::foo,&obj);
callStatic<X,&X::bar>(&obj);
return 0;
}
Template parameters have to be known at compile-time. The contents of a pointer variable that is a function's parameter depends on how this function is invoked. This is not known at compile-time!
If you know this pointer at compile-time already, you can turn the function pointer runtime parameter into a template parameter:
template<class T_CLASS, void(T_CLASS::*MemFunPtr)()>
void Example(T_CLASS* InstancePointer) {...}
Here, MemFunPtr is a template parameter that is known at compile-time and can thus be resused as a template parameter for another function or class template...
MemberFunctionPointer is a variable not a type (or compile-time constant), hence cannot be used, what you need is the real signature of that function, something like this may be better..
template<typename T_FUNC_PTR, class T_CLASS>
inline static void Example(T_FUNC_PTR fPtr, T_CLASS* InstancePointer)
{
SomeClass<T_CLASS>::Bind<T_FUNC_PTR>(fPtr, InstancePointer);
}
i.e. let the compiler deduce the type of the function pointer (NOTE: you will have to propagate the pointer to the function too), to call
Example(&foo::bar, foo_inst);
This is untested and off the top of my head, so the syntax could be slightly off...
EDIT: here is a simpler example to demonstrate the concept:
#include <iostream>
struct foo
{
void bar() { std::cout << "foo::bar()" << std::endl; }
};
template<typename T_FUNC_PTR, typename T_CLASS>
void exec(T_FUNC_PTR ptr, T_CLASS& inst)
{
(inst.*ptr)();
}
int main(void)
{
foo inst;
exec(&foo::bar, inst);
}
I am trying to write a code that calls a class method given as template parameter. To simplify, you can suppose the method has a single parameter (of an arbitrary type) and returns void. The goal is to avoid boilerplate in the calling site by not typing the parameter type. Here is a code sample:
template <class Method> class WrapMethod {
public:
template <class Object>
Param* getParam() { return ¶m_; }
Run(Object* obj) { (object->*method_)(param_); }
private:
typedef typename boost::mpl::at_c<boost::function_types::parameter_types<Method>, 1>::type Param;
Method method_;
Param param_
};
Now, in the calling site, I can use the method without ever writing the type of the parameter.
Foo foo;
WrapMethod<BOOST_TYPEOF(&Foo::Bar)> foo_bar;
foo_bar.GetParam()->FillWithSomething();
foo_bar.Run(foo);
So, this code works, and is almost what I want. The only problem is that I want to get rid of the BOOST_TYPEOF macro call in the calling site. I would like to be able to write something like WrapMethod<Foo::Bar> foo_bar instead of WrapMethod<BOOST_TYPEOF(&Foo::Bar)> foo_bar.
I suspect this is not possible, since there is no way of referring to a method signature other than using the method signature itself (which is a variable for WrapMethod, and something pretty large to type at the calling site) or getting the method pointer and then doing typeof.
Any hints on how to fix these or different approaches on how to avoid typing the parameter type in the calling site are appreciated.
Just to clarify my needs: the solution must not have the typename Param in the calling site. Also, it cannot call FillWithSomething from inside WrapMethod (or similar). Because that method name can change from Param type to Param type, it needs to live in the calling site. The solution I gave satisfies both these constraints, but needs the ugly BOOST_TYPEOF in the calling site (using it inside WrapMethod or other indirection would be fine since that is code my api users won't see as long as it is correct).
Response:
As far as I can say, there is no possible solution. This boil down to the fact that is impossible to write something like WrapMethod<&Foo::Bar>, if the signature of Bar is not known in advance, even though only the cardinality is necessary. More generally, you can't have template parameters that take values (not types) if the type is not fixed. For example, it is impossible to write something like typeof_literal<0>::type which evalutes to int and typeof_literal<&Foo::Bar>::type, which would evaluate to void (Foo*::)(Param) in my example. Notice that neither BOOST_TYPEOF or decltype would help because they need to live in the caling site and can't be buried deeper in the code. The legitimate but invalid syntax below would solve the problem:
template <template<class T> T value> struct typeof_literal {
typedef decltype(T) type;
};
In C++0x, as pointed in the selected response (and in others using BOOST_AUTO), one can use the auto keyword to achieve the same goal in a different way:
template <class T> WrapMethod<T> GetWrapMethod(T) { return WrapMethod<T>(); }
auto foo_bar = GetWrapMethod(&Foo::Bar);
Write it as:
template <typename Object, typename Param, void (Object::*F)(Param)>
class WrapMethod {
public:
Param* getParam() { return ¶m_; }
void Run(Object* obj) { (obj->*F)(param_); }
private:
Param param_;
};
and
Foo foo;
WrapMethod<Foo, Param, &Foo::Bar> foo_bar;
foo_bar.getParam()->FillWithSomething();
foo_bar.Run(foo);
EDIT: Showing a template function allowing to do the same thing without any special template wrappers:
template <typename Foo, typename Param>
void call(Foo& obj, void (Foo::*f)(Param))
{
Param param;
param.FillWithSomthing();
obj.*f(param);
}
and use it as:
Foo foo;
call(foo, &Foo::Bar);
2nd EDIT: Modifying the template function to take the initialization function as a parameter as well:
template <typename Foo, typename Param>
void call(Foo& obj, void (Foo::*f)(Param), void (Param::*init)())
{
Param param;
param.*init();
obj.*f(param);
}
and use it as:
Foo foo;
call(foo, &Foo::Bar, &Param::FillWithSomething);
If your compiler supports decltype, use decltype:
WrapMethod<decltype(&Foo::Bar)> foo_bar;
EDIT: or, if you really want to save typing and have a C++0x compliant compiler:
template <class T> WrapMethod<T> GetWrapMethod(T) { return WrapMethod<T>(); }
auto foo_bar= GetWrapMethod(&Foo::Bar);
EDIT2: Although, really, if you want it to look pretty you either have to expose users to the intricacies of the C++ language or wrap it yourself in a preprocessor macro:
#define WrapMethodBlah(func) WrapMethod<decltype(func)>
Have you considered using method templates?
template <typename T> void method(T & param)
{
//body
}
Now the compiler is able to implicitly determine parameter type
int i;
bool b;
method(i);
method(b);
Or you can provide type explicitly
method<int>(i);
You can provide specializations for different data types
template <> void method<int>(int param)
{
//body
}
When you are already allowing BOOST_TYEPOF(), consider using BOOST_AUTO() with an object generator function to allow type deduction:
template<class Method> WrapMethod<Method> makeWrapMethod(Method mfp) {
return WrapMethod<Method>(mfp);
}
BOOST_AUTO(foo_bar, makeWrapMethod(&Foo::Bar));
Okay let's have a go at this.
First of all, note that template parameter deduction is available (as noted in a couple of answers) with functions.
So, here is an implementation (sort of):
// WARNING: no virtual destructor, memory leaks, etc...
struct Foo
{
void func(int e) { std::cout << e << std::endl; }
};
template <class Object>
struct Wrapper
{
virtual void Run(Object& o) = 0;
};
template <class Object, class Param>
struct Wrap: Wrapper<Object>
{
typedef void (Object::*member_function)(Param);
Wrap(member_function func, Param param): mFunction(func), mParam(param) {}
member_function mFunction;
Param mParam;
virtual void Run(Object& o) { (o.*mFunction)(mParam); }
};
template <class Object, class Param>
Wrap<Object,Param>* makeWrapper(void (Object::*func)(Param), Param p = Param())
{
return new Wrap<Object,Param>(func, p);
}
int main(int argc, char* argv[])
{
Foo foo;
Wrap<Foo,int>* fooW = makeWrapper(&Foo::func);
fooW->mParam = 1;
fooW->Run(foo);
Wrapper<Foo>* fooW2 = makeWrapper(&Foo::func, 1);
fooW2->Run(foo);
return 0;
}
I think that using a base class is the native C++ way of hiding information by type erasure.
I have a bunch of overloaded functions that operate on certain data types such as int, double and strings. Most of these functions perform the same action, where only a specific set of data types are allowed. That means I cannot create a simple generic template function as I lose type safety (and potentially incurring a run-time problem for validation within the function).
Is it possible to create a "semi-generic compile time type safe function"? If so, how? If not, is this something that will come up in C++0x?
An (non-valid) idea;
template <typename T, restrict: int, std::string >
void foo(T bar);
...
foo((int)0); // OK
foo((std::string)"foobar"); // OK
foo((double)0.0); // Compile Error
Note: I realize I could create a class that has overloaded constructors and assignment operators and pass a variable of that class instead to the function.
Use sfinae
template<typename> struct restrict { };
template<> struct restrict<string> { typedef void type; };
template<> struct restrict<int> { typedef void type; };
template <typename T>
typename restrict<T>::type foo(T bar);
That foo will only be able to accept string or int for T. No hard compile time error occurs if you call foo(0.f), but rather if there is another function that accepts the argument, that one is taken instead.
You may create a "private" templatized function that is never exposed to the outside, and call it from your "safe" overloads.
By the way, usually there's the problem with exposing directly the templatized version: if the passed type isn't ok for it, a compilation error will be issued (unless you know your algorithm may expose subtle bugs with some data types).
You could probably work with templates specializations for the "restricted" types you want to allow. For all other types, you don't provide a template specialization so the generic "basic" template would be used. There you could use something like BOOST_STATIC_ASSERT to throw a compile error.
Here some pseudo-code to clarify my idea:
template <typename T>
void foo(T bar) {BOOST_STATIC_ASSERT(FALSE);}
template<> // specialized for double
void foo(double bar) {do_something_useful(bar);};
Perhaps a bit ugly solution, but functors could be an option:
class foo {
void operator()(double); // disable double type
public:
template<typename T>
void operator ()(T bar) {
// do something
}
};
void test() {
foo()(3); // compiles
foo()(2.3); // error
}
Edit: I inversed my solution
class foo {
template<typename T>
void operator ()(T bar, void* dummy) {
// do something
}
public:
// `int` is allowed
void operator ()(int i) {
operator ()(i, 0);
}
};
foo()(2.3); // unfortunately, compiles
foo()(3); // compiles
foo()("hi"); // error
To list an arbitrary selection of types I suppose you could use a typelist. E.g see the last part of my earlier answer.
The usage might be something like:
//TODO: enhance typelist declarations to hide the recursiveness
typedef t_list<std::string, t_list<int> > good_for_foo;
template <class T>
typename boost::enable_if<in_type_list<T, good_for_foo> >::type foo(T t);