decltype to extract function parameter type prior to calling it

Discussion in 'C++' started by gnobal, Jul 3, 2011.

  1. gnobal

    gnobal Guest

    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.
     
    gnobal, Jul 3, 2011
    #1
    1. Advertising

  2. gnobal

    Kai-Uwe Bux Guest

    gnobal wrote:

    > 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
     
    Kai-Uwe Bux, Jul 3, 2011
    #2
    1. Advertising

  3. gnobal

    gnobal Guest

    On Jul 3, 3:14 pm, Kai-Uwe Bux <> wrote:
    > gnobal wrote:
    > > 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


    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
     
    gnobal, Jul 3, 2011
    #3
  4. gnobal

    Balog Pal Guest

    "gnobal" <>
    > 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.
     
    Balog Pal, Jul 3, 2011
    #4
  5. Re: decltype to extract function parameter type prior to callingit

    Le 03/07/2011 16:54, Balog Pal a écrit :
    > "gnobal" <>
    >> 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.
    >


    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
     
    Leo \Equinox\ Gaspard, Jul 3, 2011
    #5
  6. gnobal

    gnobal Guest

    On Jul 3, 10:55 pm, "Leo \"Equinox\" Gaspard" <>
    wrote:
    > Le 03/07/2011 16:54, Balog Pal a écrit :
    >
    >
    >
    >
    >
    >
    >
    >
    >
    > > "gnobal" <>
    > >> 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.

    >
    > 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
     
    gnobal, Jul 4, 2011
    #6
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Marcin Kaliciñski

    C++0x auto and decltype

    Marcin Kaliciñski, May 9, 2005, in forum: C++
    Replies:
    6
    Views:
    1,887
    Yuriy Solodkyy
    May 11, 2005
  2. Noah Roberts

    decltype and const reference params

    Noah Roberts, Apr 7, 2010, in forum: C++
    Replies:
    7
    Views:
    992
    Joe Gottman
    Apr 8, 2010
  3. Isti
    Replies:
    2
    Views:
    746
  4. Stuart Golodetz

    decltype(*this) - C++0x

    Stuart Golodetz, Sep 29, 2010, in forum: C++
    Replies:
    4
    Views:
    1,288
    Stuart Golodetz
    Sep 29, 2010
  5. Noah Roberts

    decltype in template param list?

    Noah Roberts, Jul 22, 2011, in forum: C++
    Replies:
    4
    Views:
    1,012
    Victor Bazarov
    Jul 26, 2011
Loading...

Share This Page