decltype to extract function parameter type prior to calling it

G

gnobal

Hi,

I'm using a library that has a function that looks like this:
vector<int> getData(const vector<int>& keys, int32_t limit);
(there may be more than one datum per key)

Today I'm passing numeric_limits<int32_t>::max() as the limit, but I
was wondering whether there is a way to extract the type of the limit
parameter so that my argument will always have the right max value.
For example, if the library's author decides to make the limit an
int64_t, I wouldn't know. A worse case is if the author decides to
make it an int16_t.

I realize that this might not be the best library interface design,
but it's in a library I'm using and I can't change it. Also, maybe
there are other examples where this might be needed.

Thanks.
 
K

Kai-Uwe Bux

gnobal said:
Hi,

I'm using a library that has a function that looks like this:
vector<int> getData(const vector<int>& keys, int32_t limit);
(there may be more than one datum per key)

Today I'm passing numeric_limits<int32_t>::max() as the limit, but I
was wondering whether there is a way to extract the type of the limit
parameter so that my argument will always have the right max value.
For example, if the library's author decides to make the limit an
int64_t, I wouldn't know. A worse case is if the author decides to
make it an int16_t.

Do you mean something like:

#include <limits>

char getData ( char const &, int max ) {}

template < typename T, typename I >
I argtype_max_value ( T(fct)( T const &, I ) ) {
return ( std::numeric_limits<I>::max() );
}

#include <iostream>

int main ( void ) {
std::cout << argtype_max_value( getData ) << "\n";
}


On the other hand, I am not really sure that I understand what you mean. If
the author decides to change the library with regard to the argument type,
wouldn't that be a change in the header files? In that case, maybe the
correct place to check for it, would be the make file of your project.


Best,

Kai-Uwe Bux
 
G

gnobal

Do you mean something like:

#include <limits>

char getData ( char const &, int max ) {}

template < typename T, typename I >
I argtype_max_value ( T(fct)( T const &, I ) ) {
  return ( std::numeric_limits<I>::max() );

}

#include <iostream>

int main ( void ) {
  std::cout << argtype_max_value( getData ) << "\n";

}

On the other hand, I am not really sure that I understand what you mean. If
the author decides to change the library with regard to the argument type,
wouldn't that be a change in the header files? In that case, maybe the
correct place to check for it, would be the make file of your project.

Best,

Kai-Uwe Bux

Great... this is what I was looking for. I was hoping there would be a
way to refer to function parameters using decltype, e.g. for the
second argument:
decltype(func_param(getData, 2))
(I know this isn't general enough, but just as an idea)

I appreciate the help. Thanks a lot!

Amit
 
B

Balog Pal

gnobal said:
I'm using a library that has a function that looks like this:
vector<int> getData(const vector<int>& keys, int32_t limit);
(there may be more than one datum per key)

Today I'm passing numeric_limits<int32_t>::max() as the limit, but I
was wondering whether there is a way to extract the type of the limit
parameter so that my argument will always have the right max value.
For example, if the library's author decides to make the limit an
int64_t, I wouldn't know. A worse case is if the author decides to
make it an int16_t.

If the library changes its public interface, you're supposed to review all
pieces of your code and decide at each place what is the impact of the
changes.
I realize that this might not be the best library interface design,

It has little to do with design itself, rather with design *CHANGE*. A
public interface shall be stable. Once it is out the door you kiip it that
way, or change only in way it can not change meaning of any existing code.

So your first task is to look after your fear's foundation. There are good
chances that you jumped on a shadow. While if it is actually open to
arbitrary unannounced changes, your work shall concentrate on detecting them
rather than thinking silver bullets that mitigate.
but it's in a library I'm using and I can't change it. Also, maybe
there are other examples where this might be needed.

In general there type traits in tr1:: and boost and they IIRC include
function param types. So it is possible to find out the type and its
attached max. But I doubt it worth the effort.
 
L

Leo \Equinox\ Gaspard

Le 03/07/2011 16:54, Balog Pal a écrit :
If the library changes its public interface, you're supposed to review
all pieces of your code and decide at each place what is the impact of
the changes.


It has little to do with design itself, rather with design *CHANGE*. A
public interface shall be stable. Once it is out the door you kiip it
that way, or change only in way it can not change meaning of any
existing code.

So your first task is to look after your fear's foundation. There are
good chances that you jumped on a shadow. While if it is actually open
to arbitrary unannounced changes, your work shall concentrate on
detecting them rather than thinking silver bullets that mitigate.


In general there type traits in tr1:: and boost and they IIRC include
function param types. So it is possible to find out the type and its
attached max. But I doubt it worth the effort.

It's not the case.
And, if it was, it would fail on overloaded functions.
So, instead of making a half-working template, they chose not to do it
at all.
That's understandable.
I chose however to do one for myself (with the help of others from
forums, whose names are unknown to me), even if that would be possible
to make it fail, in order to get something. At least could it be funny
to read.

Code:
#ifndef UTIL_PARAM_HPP_INCLUDED__
#define UTIL_PARAM_HPP_INCLUDED__ 1

#include <cstddef>

namespace util {

template <size_t N, typename T> struct Param;

namespace impl {

template <typename...> struct ParamHolder { };

template <size_t N, typename T> struct ParamGetNth;

template <typename Head, typename... Tail>
struct ParamGetNth<0, ParamHolder<Head, Tail...>> {
typedef Head type;
};

template <size_t N, typename Head, typename... Tail>
struct ParamGetNth<N, ParamHolder<Head, Tail...>>
: ParamGetNth<N - 1, ParamHolder<Tail...>>
{ };

template <typename Functor, typename Ret, typename... Args>
ParamHolder<Args...> take(Ret (Functor::*) (Args...));

template <typename Functor, typename Ret, typename... Args>
ParamHolder<Args...> take(Ret (Functor::*) (Args...) const);

template <typename Functor, typename Ret, typename... Args>
ParamHolder<Args...> take(Ret (Functor::*) (Args...) volatile);

template <typename Functor, typename Ret, typename... Args>
ParamHolder<Args...> take(Ret (Functor::*) (Args...) const
volatile);

}

template <size_t N, typename Ret, typename... Args>
struct Param<N, Ret (*) (Args...)>
: impl::ParamGetNth<N, impl::ParamHolder<Args...>>
{ };

template <size_t N, typename Functor>
struct Param
: impl::ParamGetNth<N, decltype(impl::take(&Functor::operator()))>
{ };

}

#endif

Usage :
Param<ParamNumFrom0, FunctionOrFunctorTypePossibly_decltype>::type

Cheers,
Leo
 
G

gnobal

Le 03/07/2011 16:54, Balog Pal a écrit :








If the library changes its public interface, you're supposed to review
all pieces of your code and decide at each place what is the impact of
the changes.
It has little to do with design itself, rather with design *CHANGE*. A
public interface shall be stable. Once it is out the door you kiip it
that way, or change only in way it can not change meaning of any
existing code.
So your first task is to look after your fear's foundation. There are
good chances that you jumped on a shadow. While if it is actually open
to arbitrary unannounced changes, your work shall concentrate on
detecting them rather than thinking silver bullets that mitigate.
In general there type traits in tr1:: and boost and they IIRC include
function param types. So it is possible to find out the type and its
attached max. But I doubt it worth the effort.

It's not the case.
And, if it was, it would fail on overloaded functions.
So, instead of making a half-working template, they chose not to do it
at all.
That's understandable.
I chose however to do one for myself (with the help of others from
forums, whose names are unknown to me), even if that would be possible
to make it fail, in order to get something. At least could it be funny
to read.

Code:
#ifndef UTIL_PARAM_HPP_INCLUDED__
#define UTIL_PARAM_HPP_INCLUDED__ 1

#include <cstddef>

namespace util {

     template <size_t N, typename T> struct Param;

     namespace impl {

         template <typename...> struct ParamHolder { };

         template <size_t N, typename T> struct ParamGetNth;

         template <typename Head, typename... Tail>
         struct ParamGetNth<0, ParamHolder<Head, Tail...>> {
             typedef Head type;
         };

         template <size_t N, typename Head, typename... Tail>
         struct ParamGetNth<N, ParamHolder<Head, Tail...>>
             : ParamGetNth<N - 1, ParamHolder<Tail...>>
         { };

         template <typename Functor, typename Ret, typename... Args>
         ParamHolder<Args...> take(Ret (Functor::*) (Args...));

         template <typename Functor, typename Ret, typename... Args>
         ParamHolder<Args...> take(Ret (Functor::*) (Args...) const);

         template <typename Functor, typename Ret, typename... Args>
         ParamHolder<Args...> take(Ret (Functor::*) (Args...) volatile);

         template <typename Functor, typename Ret, typename... Args>
         ParamHolder<Args...> take(Ret (Functor::*) (Args...) const
                                                              volatile);

     }

     template <size_t N, typename Ret, typename... Args>
     struct Param<N, Ret (*) (Args...)>
         : impl::ParamGetNth<N, impl::ParamHolder<Args...>>
     { };

     template <size_t N, typename Functor>
     struct Param
         : impl::ParamGetNth<N, decltype(impl::take(&Functor::operator()))>
     { };

}

#endif

Usage :
Param<ParamNumFrom0, FunctionOrFunctorTypePossibly_decltype>::type

Cheers,
Leo

Thanks everyone for your insights and code.

Balog, you're absolutely right that I should review library changes
and that I may be jumping on a shadow. I make the best efforts to
review changes in libraries that I use. Sometimes, however, it's so
much work that I was hoping to avoid some of it.

Leo, thanks a lot for the code. Could have never written this
myself :)

Amit
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top