Google
 
Webnews.only-4-geeks.com
Interesting places
news.only-4-geeks.com Forum Index » C++

Detecting memfun staticness

 
Jump to:  
 
Joaquín M López Muñoz
PostPosted: Thu Aug 28, 2008 8:34 pm    Post subject: Detecting memfun staticness
       
Say I've got the following template function

template<typename T>
void call_f(int x)
{
T t;
t.f(x);
}

whose purpose is to invoke t.f(x) on an object of type T:

struct foo
{
void f(int){}
};

struct bar
{
static void f(int){};
};

...

call_f<foo>(5);
call_f<bar>(5);

And now I'd like to optimize call_f's implementation by avoiding the
creation of the T object when it is not necessary (as in bar, whose
memfun
f is static). The following will do for simple cases like foo and bar
above:

template<typename T,typename R,typename A>
void call_f_impl(int x,R(*)(A))
{
T::f(x);
}

template<typename T,typename Q>
void call_f_impl(int x,Q)
{
T t;
t.f(x);
}

template<typename T>
void call_f(int x)
{
call_f_impl<T>(x,&T::f);
}

but fails when f is a memfun template:

struct baz
{
template<typename T>
void f(T){}
};

...

call_f<baz>(5);

For instance, Comeau says:

"ComeauTest.c", line 17: error: no instance of overloaded function
"call_f_impl"
matches the argument list
The argument types that you used are: (int, <unknown-
type>)
call_f_impl<T>(x,&T::f);
^
detected during instantiation of "void call_f<T>(int)
[with T=baz]"
at line 42

1 error detected in the compilation of "ComeauTest.c".


Any idea about how to solve this in a more comprehensive way?

Thank you in advance,

Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo


--
[ See LINK for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 

 
Roman.Perepelitsa@gmail.c
PostPosted: Sat Aug 30, 2008 2:40 pm    Post subject: Re: Detecting memfun staticness
       
On 28 Aug, 22:34, Joaquín M López Muñoz <joaq...@tid.es> wrote:
Quote:
Say I've got the following template function

template<typename T
void call_f(int x)
{
T t;
t.f(x);
}

whose purpose is to invoke t.f(x) on an object of type T:

struct foo
{
void f(int){}
};

struct bar
{
static void f(int){};
};

...

call_f<foo>(5);
call_f<bar>(5);

And now I'd like to optimize call_f's implementation by avoiding the
creation of the T object when it is not necessary (as in bar, whose
memfun
f is static).

Example of usage:

struct non_static_int
{
void f(int);
};

struct static_int
{
static void f(int);
};

struct non_static_short
{
void f(short);
};

struct static_short
{
static void f(short);
};

struct non_static_tmpl
{
template <typename T>
void f(T);
};

struct static_tmpl
{
template <typename T>
static void f(T);
};

struct non_static_int_returns_int {
int f(int);
};

struct static_int_returns_int {
static int f(int);
};


#define STATIC_ASSERT(expr) \
do { char static_checker[(expr) ? 1 : -1]; } while (false)

#define CHECK_TRUE(type) \
STATIC_ASSERT((is_static_call_possible<type, void(int)>::value))

#define CHECK_FALSE(type) \
STATIC_ASSERT((!is_static_call_possible<type, void(int)>::value))

int main() {
CHECK_TRUE(static_int);
CHECK_TRUE(static_short);
CHECK_TRUE(static_tmpl);
CHECK_TRUE(static_int_returns_int);

CHECK_FALSE(non_static_int);
CHECK_FALSE(non_static_short);
CHECK_FALSE(non_static_tmpl);
CHECK_FALSE(non_static_int_returns_int);
}

So basically is_static_call_possible<type, r(arg1)>::result
is true if and only if expression type::f(*(arg1)0) is well
formed and its result can be implicitly converted to type r.

Implementation (based on
LINK):

template <typename type>
class void_exp_result {};

template <typename type, typename U>
U const& operator,(U const&, void_exp_result<type>);

template <typename type, typename U>
U& operator,(U&, void_exp_result<type>);

template <typename type, typename call_details>
struct is_static_call_possible
{
private:
class yes {};
class no { yes m[2]; };

struct derived : public type
{
using type::f;
static no f(...);
};

template <typename T, typename due_type>
struct return_value_check
{
static yes deduce(due_type);
static no deduce(...);
static no deduce(no);
static no deduce(void_exp_result<type>);
};

template <typename T>
struct return_value_check<T, void>
{
static yes deduce(...);
static no deduce(no);
};

template <typename F>
struct impl;

template <typename arg1, typename r>
struct impl<r(arg1)>
{
static const bool value =
sizeof(
return_value_check<type, r>::deduce(
(derived::f(*(arg1*)0), void_exp_result<type>()))
) == sizeof(yes);
};

// Add specializations for different number of args.

public:
static const bool value = impl<call_details>::value;
};

Roman Perepelitsa.


--
[ See LINK for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 

 
Daniel Krügler
PostPosted: Sat Aug 30, 2008 3:28 pm    Post subject: Re: Detecting memfun staticness
       
On 28 Aug., 22:34, Joaquín M López Muñoz <joaq...@tid.es> wrote:
Quote:
Say I've got the following template function

template<typename T
void call_f(int x)
{
T t;
t.f(x);
}

whose purpose is to invoke t.f(x) on an object of type T:

struct foo
{
void f(int){}
};

struct bar
{
static void f(int){};
};

...

call_f<foo>(5);
call_f<bar>(5);

And now I'd like to optimize call_f's implementation by avoiding the
creation of the T object when it is not necessary (as in bar, whose
memfun
f is static). The following will do for simple cases like foo and bar
above:

template<typename T,typename R,typename A
void call_f_impl(int x,R(*)(A))
{
T::f(x);
}

template<typename T,typename Q
void call_f_impl(int x,Q)
{
T t;
t.f(x);
}

template<typename T
void call_f(int x)
{
call_f_impl<T>(x,&T::f);
}

but fails when f is a memfun template:

struct baz
{
template<typename T
void f(T){}
};

...

call_f<baz>(5);

For instance, Comeau says:

"ComeauTest.c", line 17: error: no instance of overloaded function
"call_f_impl"
matches the argument list
The argument types that you used are: (int, <unknown-
type>)
call_f_impl<T>(x,&T::f);
^
detected during instantiation of "void call_f<T>(int)
[with T=baz]"
at line 42

1 error detected in the compilation of "ComeauTest.c".

Yes, the compiler is correct to diagnose this, because your
deduction case is explicitly described in [temp.deduct.type]/16:

"A template-argument can be deduced from a pointer to function
or pointer to member function argument if the set of overloaded
functions does not contain function templates and at most one
of a set of overloaded functions provides a unique match."

This wording has been drastically shortened in the current
draft, but the essence is the same: Type deduction fails if
the argument is itself a template.

Quote:
Any idea about how to solve this in a more comprehensive way?

Not a perfect one, unfortunately :-(

A perfect one would probably try to apply SFINAE to
differentiate cases, where the expression T::f(a)
is either valid or invalid (with a of int type).
I could not come up with any example that fulfills
silent deduction failure. Just as an example, one
might consider to try

---------------------------------
#include <stddef.h>
#include <typeinfo>
#include <boost/type_traits/remove_reference.hpp>

typedef char Yes;
typedef char (&No)[2];

template<typename T>
struct type_wrapper {};

template<size_t N>
struct size_wrapper {};

template<typename T, typename Arg>
struct IsStaticMemFunF1 {
private:
static typename boost::remove_reference<Arg>::type& arg();
template<typename U>
static Yes check(type_wrapper<U>*,
size_wrapper<sizeof(typeid(U::f(arg())))>* = 0);
static No check(...);
public:
static const bool value =
sizeof(check(static_cast<type_wrapper<T>*>(0))) == sizeof(Yes);
};

struct foo {
void f(int){}
};

struct bar {
static void f(int){}
};

struct baz {
template<typename T>
void f(T){}
};

struct kuz {
template<typename T>
static void f(T){}
};

typedef bool ok1 [!IsStaticMemFunF1<foo, int>::value ? 1 : -1];
typedef bool ok2 [IsStaticMemFunF1<bar, int>::value ? 1 : -1];
typedef bool ok3 [!IsStaticMemFunF1<baz, int>::value ? 1 : -1];
typedef bool ok4 [IsStaticMemFunF1<kuz, int>::value ? 1 : -1];

int main() {
}
---------------------------------

but this is not covered by the standard and will not
work. The upcoming standard is going to extend these
cases and given that extension I think above example
should work. But let's speak of todays compiler techno-
logy (In C++0x you would use a simple concept and be
ready):

I think you can solve your problem in C++03, if you
accept the restriction that static function call
mechanism is only invoked, when the actual function is
convertible to void(*)(int). This applies for all your
examples, but I don't know whether this is an acceptable
way to go for you, because it means that non-void return
types would be ignored for the static route, similar
ignorance would apply for arguments not identical to
int. If you allow slight deviations (e.g. void(*)(const int&))
this could be simply added to the here proposed very
simple SFINAE deduction:

-----------------------------
template<bool E, typename T = void>
struct enable_if{};

template<typename T>
struct enable_if<true, T>{ typedef T type; };

typedef char Yes;
typedef char (&No)[2];

template<typename T>
struct type_wrapper {};

template<typename T, typename R, typename Arg>
struct ConvertibleFunPtr {
private:
template<R(*)(Arg)>
struct func_wrapper {};
template<typename U>
static Yes check(type_wrapper<U>*,
func_wrapper<&U::f>* = 0);
static No check(...);
public:
static const bool value =
sizeof(check(static_cast<type_wrapper<T>*>(0))) == sizeof(Yes);
};

template<typename T>
typename enable_if<ConvertibleFunPtr<T, void, int>::value>::type
call_f_impl(int x)
{
T::f(x);
}

template<typename T>
typename enable_if<!ConvertibleFunPtr<T, void, int>::value>::type
call_f_impl(int x)
{
T t;
t.f(x);
}

template<typename T>
void call_f(int x)
{
call_f_impl<T>(x);
}

struct foo {
void f(int){}
};

struct bar {
static void f(int){}
};

struct baz {
template<typename T>
void f(T){}
};

struct kuz {
template<typename T>
static void f(T){}
};

typedef bool ok1 [!ConvertibleFunPtr<foo, void, int>::value ? 1 : -1];
typedef bool ok2 [ConvertibleFunPtr<bar, void, int>::value ? 1 : -1];
typedef bool ok3 [!ConvertibleFunPtr<baz, void, int>::value ? 1 : -1];
typedef bool ok4 [ConvertibleFunPtr<kuz, void, int>::value ? 1 : -1];

int main() {
call_f<foo>(5);
call_f<bar>(5);
call_f<baz>(5);
call_f<kuz>(5);
}
----------------------------------------------------

HTH & Greetings from Bremen,

Daniel



--
[ See LINK for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 

 
Joaquín M López Muñoz
PostPosted: Mon Sep 01, 2008 2:04 am    Post subject: Re: Detecting memfun staticness
       
Hi Roman,

Your technique is very ingenious, but I've got some doubts
regarding the validity of the assumptions it relies on. If
I'm understanding the code, it all revolves around struct
derived:

Quote:
struct derived : public type
{
using type::f;
static no f(...);
};

and an assumed property that overload resolution of

derived::f(*(arg*)0)

will prefer "static no f(...)" over other overloads of f in type
if these overloads happen not to be static. I have been reading
the standard and cannot find any base for this assumption
(although admittedly I'm no standard guru). Do you have a clue
about this?

FWIW, the code you provide does not work under MSVC++ 8.0.
Errors like the following show:

error C2352: 'non_static_int::f' : illegal call of non-static
member function[...]

which suggests that the property stated above (ruling out
non-static candidates) is not observed by this compiler.
GCC, on the other hand, accepts your code fine.

I've investigated this issue separately from my original
problem and will post a specific post now to clc++m. Maybe
you can rejoin the discussion there.

Thank you,

Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo


--
[ See LINK for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 

 
Roman.Perepelitsa@gmail.c
PostPosted: Mon Sep 01, 2008 10:58 am    Post subject: Re: Detecting memfun staticness
       
On 1 Sep, 04:04, Joaquín M López Muñoz <joaq...@tid.es> wrote:
Quote:
Hi Roman,

Your technique is very ingenious, but I've got some doubts
regarding the validity of the assumptions it relies on. If
I'm understanding the code, it all revolves around struct
derived:

struct derived : public type
{
using type::f;
static no f(...);
};

and an assumed property that overload resolution of

derived::f(*(arg*)0)

will prefer "static no f(...)" over other overloads of f in type
if these overloads happen not to be static. I have been reading
the standard and cannot find any base for this assumption
(although admittedly I'm no standard guru). Do you have a clue
about this?

FWIW, the code you provide does not work under MSVC++ 8.0.
Errors like the following show:

error C2352: 'non_static_int::f' : illegal call of non-static
member function[...]

which suggests that the property stated above (ruling out
non-static candidates) is not observed by this compiler.
GCC, on the other hand, accepts your code fine.

I've investigated this issue separately from my original
problem and will post a specific post now to clc++m. Maybe
you can rejoin the discussion there.

Thank you,

Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo

I believe my code is indeed based on gcc bug (sorry,
I should've tried it with other compilers before posting).
I can't find relevant text in the standard but I have a gut
feeling that it is the case.

Leaving theoretical problems aside, there is a practical
workaround that might work for you. You can change the
logic of dispatching function to the following:
- if it is possible to call nonstatic function, then
call it
- otherwise try to call static function
For that you need "is_nonstatic_call_possible", which
you can find here: LINK

Roman Perepelitsa.


--
[ See LINK for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 

 
Greg Herlihy
PostPosted: Mon Sep 01, 2008 7:39 pm    Post subject: Re: Detecting memfun staticness
       
On Aug 28, 1:34 pm, Joaquín M López Muñoz <joaq...@tid.es> wrote:
Quote:
Say I've got the following template function

template<typename T
void call_f(int x)
{
T t;
t.f(x);
}

whose purpose is to invoke t.f(x) on an object of type T:

struct foo
{
void f(int){}
};

struct bar
{
static void f(int){};
};
...
call_f<foo>(5);
call_f<bar>(5);

And now I'd like to optimize call_f's implementation by avoiding the
creation of the T object when it is not necessary (as in bar, whose
memfun f is static).

To avoid the overhead of initializing a "T" object each time
call_f<T>() is invoked, simply have the T object declared inside
call_f() - be static as well:

template <class T>
void call_f(int x)
{
static T t;

t.f(x);
}

Greg


--
[ See LINK for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 

 
Joaquín M López Muñoz
PostPosted: Mon Sep 01, 2008 7:40 pm    Post subject: Re: Detecting memfun staticness
       
On 1 sep, 12:58, "Roman.Perepeli...@gmail.com"
<Roman.Perepeli...@gmail.com> wrote:
Quote:
On 1 Sep, 04:04, Joaquín M López Muñoz <joaq...@tid.es> wrote:
[...]
Leaving theoretical problems aside, there is a practical
workaround that might work for you. You can change the
logic of dispatching function to the following:
- if it is possible to call nonstatic function, then
call it
- otherwise try to call static function
For that you need "is_nonstatic_call_possible", which
you can find here:http://preview.tinyurl.com/5dkg9v

I'm afraid this won't work either: is_nonstatic_call_possible
(named is_call_possible in the original source) only determines
whether a call of the form p->f(arg) is valid, but alas static
member functions are also covered by this call syntax:

struct foo
{
static void f(){}
};

int main()
{
foo x;
x.f(); // OK, despite foo::f being static
}

So we're back to square one :(

Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo


--
[ See LINK for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 

 
Joaquín M López Muñoz
PostPosted: Mon Sep 01, 2008 10:04 pm    Post subject: Re: Detecting memfun staticness
       
On 1 sep, 21:39, Greg Herlihy <gre...@mac.com> wrote:
Quote:
On Aug 28, 1:34 pm, Joaquín M López Muñoz <joaq...@tid.es> wrote:



Say I've got the following template function

template<typename T
void call_f(int x)
{
T t;
t.f(x);
}
[...]
And now I'd like to optimize call_f's implementation by avoiding the
creation of the T object when it is not necessary (as in bar, whose
memfun f is static).

To avoid the overhead of initializing a "T" object each time
call_f<T>() is invoked, simply have the T object declared inside
call_f() - be static as well:

template <class T
void call_f(int x)
{
static T t;

t.f(x);
}

Well, my probem statement is a simplification of the real scenario;
actually, I'm not creating t, but rather retrieving a reference to
it through a Meyers singleton, something like this:

template<class T>
struct singleton
{
static T& get()
{
static T t;
return t;
}
};

template <class T>
void call_f(int x)
{
singleton<T>::get().f(x);
}

The problem is that the compiler does not optimize
the singleton<T>::get() call away when T::f is static because
obtaining the singleton reference has side effects, namely the
creation of t the first time get() is called. The translation
of your proposal to this scenario:

template <class T>
void call_f(int x)
{
T& t=singleton<T>::get();
t.f(x);
}

is also suboptimal because the *presence* of a static local incurs
an execution overhead every time call_f is invoked, precisely
for the same reason as above, first-time-creation code must be
executed on every call_f invocation.

Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo


--
[ See LINK for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 

 
Greg Herlihy
PostPosted: Wed Sep 03, 2008 8:36 am    Post subject: Re: Detecting memfun staticness
       
On Sep 1, 3:04 pm, Joaquín M López Muñoz <joaq...@tid.es> wrote:
Quote:
On 1 sep, 21:39, Greg Herlihy <gre...@mac.com> wrote:

To avoid the overhead of initializing a "T" object each time
call_f<T>() is invoked, simply have the T object declared inside
call_f() - be static as well:

template <class T
void call_f(int x)
{
static T t;

t.f(x);
}

The problem is that the compiler does not optimize
the singleton<T>::get() call away when T::f is static because
obtaining the singleton reference has side effects, namely the
creation of t the first time get() is called. The translation
of your proposal to this scenario:

template <class T
void call_f(int x)
{
T& t=singleton<T>::get();
t.f(x);
}

is also suboptimal because the *presence* of a static local incurs
an execution overhead every time call_f is invoked, precisely
for the same reason as above, first-time-creation code must be
executed on every call_f invocation.

The call to singleton<T>::get() will be executed only once - if the T&
reference variable inside call_f() is declared static as well:

template <class T>
void call_f(int x)
{
static T& t = singleton<T>::get();

t.f(x);
}

Greg



--
[ See LINK for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 

 
Joaquín M López Muñoz
PostPosted: Wed Sep 03, 2008 8:58 pm    Post subject: Re: Detecting memfun staticness
       
On 3 sep, 10:36, Greg Herlihy <gre...@mac.com> wrote:
Quote:
On Sep 1, 3:04 pm, Joaquín M López Muñoz <joaq...@tid.es> wrote:

The call to singleton<T>::get() will be executed only once - if the T&
reference variable inside call_f() is declared static as well:

template <class T
void call_f(int x)
{
static T& t = singleton<T>::get();

t.f(x);
}

Yep, but we incur the first-time-creation code penalty again,
this time associated with the static local t :(

Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo


--
[ See LINK for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 

Page 1 of 1 .:.

Google
 
Webnews.only-4-geeks.com

Windows Update | C++ | C | PHP | JavaScript | Photoshop | Programming | Windows 2000 | Python | Windows XP | Object | Flash | Flash - ActionScript | Paint Shop Pro | Excel | PowerPoint | Access | Word | Windows 98 | Internet Explorer 6.0 | CorelDraw12 | Java | XML | asm x86 | Linux Mandrake | Linux RedHat | Outlook |  | news from newsgroups |_ | s

Web Templates

Awesome Website Templates ©

konta firmowe lokalizacja baner media mieszkania do wynajęcia zabrze zakłady bukmacherskie stroje sportowe