Thread: C++0x: Variadic template of the same type

  1. #1
    Registered User
    Join Date
    Oct 2008
    Posts
    1,262

    C++0x: Variadic template of the same type

    Hello all,

    I've only just started reading about C++0x. I'm trying to make a function that takes as many arguments as the caller likes, but they're all from the same type. Let's say integers for now.
    Now, I tried something like this, but this doesn't work:
    Code:
    void f(int... arguments)
    {
    }
    Something like this does, but doesn't take care of everything being the same type:
    Code:
    template<typename ... T>
    void f(T... arguments)
    {
    }
    Any ideas on how to get that to work?


    Thanks in advance

  2. #2
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    why not to pass vector of integers or whatsoever...?
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  3. #3
    Registered User
    Join Date
    Oct 2008
    Posts
    1,262
    Quote Originally Posted by vart View Post
    why not to pass vector of integers or whatsoever...?
    Because I'm lazy :P. Basically, I want the programmer to be able to simply call:
    Code:
    f(1, 2, 3);
    Actually, in my case, the number of arguments should depend on an integer specified to a template function. Right now, I managed to get what I wanted like this:
    Code:
      template<typename ... T>
      void set(const T&... values)
      {
        static_assert(sizeof...(values) == S, "Invalid number of arguments");
    
        const T array[S] = {values...};
        std::copy(array, array + S, _values);
      }
    But is there not a cleaner way to allow only one type for the arguments?

  4. #4
    The larch
    Join Date
    May 2006
    Posts
    3,573
    I think you might rather use std::initializer_list in which case the call would become:

    Code:
        set({1, 2, 3, 4});
    My compiler doesn't seem to accept unpacking arguments in the array initialization. Don't know if it is not meant to, in which case you might use recursion to copy each item to the array.

    If you want to assert at compile-time that the types are the same, then if there is no existing trait for it, you can write one yourself.

    Code:
    #include <type_traits>
    
    template <class ...T>
    struct are_same;
    
    template <class A, class B, class ...T>
    struct are_same<A, B, T...>
    {
        static const bool value = std::is_same<A, B>::value && are_same<B, T...>::value;
    };
    
    template <class A>
    struct are_same<A>
    {
        static const bool value = true;
    };
    
    template <class ...T>
    void foo(T... t)
    {
        static_assert(are_same<T...>::value, "Types are different");
    }
    
    int main()
    {
        foo(1, 2, 3, 4);
        //foo(1, 2, 3, '4');
    }
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  5. #5
    Registered User
    Join Date
    Oct 2008
    Posts
    1,262
    Thanks guys!

    Anon: That syntax is actually what I wanted to avoid. I don't like it. And my function now works, even though it doesn't provide the best readable error message if the types of the parameters can't be converted to the type.
    Besides, I think don't think you can test the size of an initializer_list at compile time, which is a huge downside for me as well.

    While your idea for type checking sounds good, there's one pitfall for that (also, it's not supported yet for gcc, I think): The compiler has to be able to call enough recursive templates to do that. I have no idea what the default number is for g++, though. So it might require a couple of hundred parameters before that's a problem. Or so I think, at least, as it will become a static expression that's compiled away anything I guess... Any thoughts?

    EDIT: Actually, I was wrong, the compiler does support it. Sweet ;-).
    Last edited by EVOEx; 03-31-2010 at 08:35 AM.

  6. #6
    Registered User
    Join Date
    Oct 2008
    Posts
    1,262
    As an addition, I didn't realize C++0x support was still so buggy. I've already had one segmentation fault (for something like this):
    Code:
    template<int S, typename T1, typename T2>
    auto operator+(const A<S, T1> &first, const A<S, T1> &second) -> A<S, decltype(first.f1() + first.f2())>
    And once I hack-fixed it to something very ugly:
    Code:
    template<int S, typename T1, typename T2, typename R = decltype(*(T1*)0 + *(T2*)0)>
    A<S, R> operator+(const A<S, T1> &first, const A<S, T1> &second)
    It did work, however at that point the following would no longer work:
    Code:
    std::cout << (a_instance1 + a_instance2) << std::endl;
    As it would write a pointer value to the stream, rather than calling the operator<< I implemented for the stream.


    Right. C++0x support. Is. Not. Good.


    EDIT: (again) Well, okay, the last bit was my fault for not making the stream operator<< allow const references but only non-const. Damnit.
    Last edited by EVOEx; 03-31-2010 at 09:15 AM.

  7. #7
    The larch
    Join Date
    May 2006
    Posts
    3,573
    I have no idea what the default number is for g++, though.
    For me it is 500 by default (but can be changed).

    I think it would also be possible to use two different specializations instead of std::is_same:

    Code:
    template <class A, class ...T>
    struct are_same<A, A, T...>
    {
        static const bool value = are_same<A, T...>::value;
    };
    
    template <class A, class B, class ...T>
    struct are_same<A, B, T...>
    {
        static const bool value = false;
    };
    Otherwise I'm not entirely sure whether && is short-circuiting in template meta-programming. (I seem to remember once trying to use ?: but it evaluated both operands regardless.)
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  8. #8
    Registered User
    Join Date
    Oct 2008
    Posts
    1,262
    Thanks anon ;-). Works as a charm.
    Though I still consider this a missing feature in C++0x if there is no better way.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. typename madness
    By zxcv in forum C++ Programming
    Replies: 4
    Last Post: 05-13-2006, 10:35 PM
  2. Using VC Toolkit 2003
    By Noobwaker in forum Windows Programming
    Replies: 8
    Last Post: 03-13-2006, 07:33 AM
  3. Erros in Utility Header File
    By silk.odyssey in forum C++ Programming
    Replies: 4
    Last Post: 12-22-2003, 06:17 AM
  4. Template specialization
    By CornedBee in forum C++ Programming
    Replies: 2
    Last Post: 11-25-2003, 02:02 AM
  5. oh me oh my hash maps up the wazoo
    By DarkDays in forum C++ Programming
    Replies: 5
    Last Post: 11-30-2001, 12:54 PM