9

I have a class template and I can't seem to figure out how to perform a Variadic Template style instantiation.

Here is the "code" so far of what I'm looking for:

template<typename _Classname, typename... Args>
class CFunctorStartExT 
{
  friend class CXXFactory;
protected:
  template<typename U>
  CFunctorStartExT(typename U& _functor, Args&... args) :
    m_Functor(_functor),
    m_args(args)
  {
  }
  virtual bool ProcessLoop(CSomeClass* pThread)
  {
    return m_Functor(pThread, m_args);
  }

protected:
  _Classname& m_Functor;
  Args... m_args;
};

Obviously this won't compile :). The idea is to create a class that can store the values passed in (if any.. it might just have _Classname/U defined) on the constructor so they can be retrieved later to pass to m_Functor in another function.

First: can Variadic Template even be done in VS2010? I am getting compile problems just with the template declaration error C2143: syntax error : missing ',' before '...' from the line template<typename _Classname, typename... Args>

Second, can what I am trying to accomplish be done? Thanks!

BabelFish
  • 899
  • 2
  • 9
  • 20
  • 2
    Names beginning with an underscore followed by a capital letter, like `_Classname`, are reserved and you should not use them in your program. – James McNellis Jan 21 '11 at 21:06
  • oh.. reserved for what/who? I have been trying to change my naming convention.. (change from the m_, g_, etc) – BabelFish Jan 21 '11 at 21:09
  • 1
    See [this](http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier). – GManNickG Jan 21 '11 at 21:45

3 Answers3

28

Visual C++ 2010 does not support variadic templates.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • lol.. bummer.. :( anyway to accomplish what I am doing via variadic macros? I know that std::make_shared has a variadic style but I get lost in all of the defines. – BabelFish Jan 21 '11 at 21:10
  • 3
    Does that mean that somebody at Microsoft did a lot of copying and pasting to get a limited [tuple class](http://msdn.microsoft.com/en-us/library/bb982837.aspx)? – Thomas Jan 21 '11 at 21:11
  • 1
    no.. they have this very intricate macro define "mechanism" that defines and undefines to create the necessary classes.. from what I can tell. you see it in files xxshared and xfwrap and xfwrap1 etc – BabelFish Jan 21 '11 at 21:16
  • 3
    For completeness sake, with tears in my eyes: http://connect.microsoft.com/VisualStudio/feedback/details/463677/support-variadic-templates – xtofl Feb 08 '11 at 20:23
  • @James McNellis: Apparently they won't be in VS11. – Alexandre C. Sep 30 '11 at 20:10
3

I believe the following will do what you want. First you need a utility:

// make_tuple_indices

template <size_t...> struct tuple_indices {};

template <size_t _Sp, class _IntTuple, size_t _Ep>
struct make_indices_imp;

template <size_t _Sp, size_t ..._Indices, size_t _Ep>
struct make_indices_imp<_Sp, tuple_indices<_Indices...>, _Ep>
{
    typedef typename make_indices_imp<_Sp+1, tuple_indices<_Indices..., _Sp>, _Ep>::type type;
};

template <size_t _Ep, size_t ..._Indices>
struct make_indices_imp<_Ep, tuple_indices<_Indices...>, _Ep>
{
    typedef tuple_indices<_Indices...> type;
};

template <size_t _Ep, size_t _Sp = 0>
struct make_tuple_indices
{
    static_assert(_Sp <= _Ep, "make_tuple_indices input error");
    typedef typename make_indices_imp<_Sp, tuple_indices<>, _Ep>::type type;
};

Then you can use this to help you expand a tuple holding your arguments:

template<typename _Classname, typename... Args>
class CFunctorStartExT 
{
  friend class CXXFactory;
protected:
  template<typename U>
  CFunctorStartExT(U& _functor, Args&... args) :
    m_Functor(_functor),
    m_args(args...)
  {
  }

  virtual bool ProcessLoop(CSomeClass* pThread)
  {
    return ProcessLoop(pThread,
                       typename make_tuple_indices<sizeof...(Args)>::type());
  }

protected:
  _Classname& m_Functor;
  std::tuple<Args...> m_args;

private:
    template <std::size_t ...Indx>
    bool ProcessLoop(CSomeClass* pThread, tuple_indices<Indx...>)
    {
        return m_Functor(pThread, std::get<Indx>(m_args)...);
    }
};

As far as VS2010 variadic template support: I have no idea.

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • 2
    this would be great if VS2010 could support "typename..." – BabelFish Jan 24 '11 at 16:21
  • Thanks this solved a quite similar scenario I needed help with. Would it be okay to include your tuple_indices/make_tuple_indices code in an MIT-like licensed library? Licence can be viewed here: http://www.angelcode.com/angelscript/sdk/docs/manual/doc_license.html – Functastic Apr 20 '11 at 21:26
  • The code shown above actually already is MIT licensed, though I didn't bother with the license for this snippet, and it is a common technique. Here is where it came from: http://libcxx.llvm.org/ in the header __tuple : http://llvm.org/svn/llvm-project/libcxx/trunk/include/__tuple . It would be great if you could include the copyright in __tuple and the reference to LICENSE.TXT. – Howard Hinnant Apr 20 '11 at 23:13
  • Okay thanks again. I shall be looking forward to future articles on these "common techniques" for effective use of variadic templates. I've only just started to work with them and although my code is much clearer with variadic templates (rather than preprocessor hacks), I was quite disappointed to find that there is no language level facility to obtain the index of expanded parameters/arguments. No doubt there will be an avalanche of new books now that C++11 is nearing ratification, however. – Functastic Apr 21 '11 at 00:00
-2

Variadic templates are a patch upon a kludge upon a hack -- you're not going to enjoy this. The way to do this (off the top of my head) is to use template specialization together with inheritance. Something along these lines:

template<typename Classname, typename... Args>
class CFunctorStartExT;

template<typename Classname, typename Arg0, typename... Args>
class CFunctorStartExT : private CFunctorStartExT<Classname, Args...> {
protected:
  Arg0 m_arg;
};

template<typename Classname>
class CFunctorStartExT {
protected:
  Classname &m_Functor;
};

I've never done this before, and haven't tested it, but this is the general idea. You could have a look at a std::tuple implementation for something that actually works.

Thomas
  • 174,939
  • 50
  • 355
  • 478