简体   繁体   中英

Visual Studio 2012 : no variadic templates : a solution?

I have a class that needs to support a dynamic set of type arguments, but VS2012 does not support variadic templates. (VS2013 and the compiler CTP do support variadic templates, but I can't use them. Nor can I use Boost.)

So, I'm trying to find a solution by using "templates specialization". Below is what I have so far. (Notice that if you rename Signaler2 by Signaler... there are some compilation issues.)

Any ideas on how to solve this problem?

#include <functional>
#include <vector>

using namespace std;

namespace spectralCore
{

#pragma region Signaler2<T1, T2>

// A signal object to handle signal/events notifications.
template<typename T1, typename T2>
class Signaler2
{
public:
  typedef std::function<void (T1,T2)> Func;

public:
  void Call(T1 arg1, T2 arg2)
  {
    for(auto i = _handlers.begin(); i != _handlers.end(); i++)
      (*i)(arg1, arg2);

    for(auto i = _postHandlers.begin(); i != _postHandlers.end(); i++)
      (*i)(arg1, arg2);
  }

  void operator ()(T1 arg1, T2 arg2)
  {
    Call(arg1, arg2);
  }

  Signaler2& operator*=(Func f)
  {
    _postHandlers.push_back( f );
    return *this;
  }

  Signaler2& operator/=(Func f)
  {
    for(auto i = _postHandlers.begin(); i != _postHandlers.end(); i++)
    {
      if ( (*i).template target<void (T1,T2)>() == f.template target<void (T1,T2)>() )
      {
        _postHandlers.erase( i );
        break;
      }
    }

    return *this;
  }

  Signaler2& operator+=(Func f)
  {
    _handlers.push_back( f );
    return *this;
  }

  Signaler2& operator-=(Func f)
  {
    for(auto i = _handlers.begin(); i != _handlers.end(); i++)
    {
      if ( (*i).template target<void (T1,T2)>() == f.template target<void (T1,T2)>() )
      {
        _handlers.erase( i );
        break;
      }
    }

    return *this;
  }

  bool IsRegistered(Func f)
  {
    for(auto i = _handlers.begin(); i != _handlers.end(); i++)
      if ( (*i).template <void (T1,T2)>() == f.template target<void (T1,T2)>() )
        true;

    return false;
  }

private:
  std::vector<Func> _handlers;
  std::vector<Func> _postHandlers;
};

#pragma endregion

#pragma region Signaler<T1>

// A signal object to handle signal/events notifications.
//template<typename T1> class Signaler<T1,void>
template<typename T1>
class Signaler
{
public:
  typedef std::function<void (T1)> Func;

public:
  void Call(T1 arg)
  {
    for(auto i = _handlers.begin(); i != _handlers.end(); i++)
      (*i)( arg );

    for(auto i = _postHandlers.begin(); i != _postHandlers.end(); i++)
      (*i)( arg );
  }

  void operator ()(T1 arg)
  {
    Call( arg );
  }

  Signaler& operator+=(Func f)
  {
    _handlers.push_back( f );
    return *this;
  }

  Signaler& operator-=(Func f)
  {
    for(auto i = _handlers.begin(); i != _handlers.end(); i++)
    {
      if ( (*i).template target<void (T1)>() == f.template target<void (T1)>() )
      {
        _handlers.erase( i );
        break;
      }
    }

    return *this;
  }

  Signaler& operator*=(Func f)
  {
    _postHandlers.push_back( f );
    return *this;
  }

  Signaler& operator/=(Func f)
  {
    for(auto i = _postHandlers.begin(); i != _postHandlers.end(); i++)
    {
      if ( (*i).template target<void (T1)>() == f.template target<void (T1)>() )
      {
        _postHandlers.erase( i );
        break;
      }
    }

    return *this;
  }

  bool IsRegistered(Func f)
  {
    for(auto i = _handlers.begin(); i != _handlers.end(); i++)
      if ( (*i).template target<void (T1)>() == f.template target<void (T1)>() )
        true;

    return false;
  }

private:
  std::vector<Func> _handlers;     // First step handlers
  std::vector<Func> _postHandlers; // Second step handlers
};

#pragma endregion

#pragma region Signaler<void>

// A signal object to handle signal/events notifications.
template<>
class Signaler<void>
{
public:
  typedef std::function<void (void)> Func;

public:
  void Call()
  {
    for(auto i = _handlers.begin(); i != _handlers.end(); i++)
      (*i)();

    for(auto i = _postHandlers.begin(); i != _postHandlers.end(); i++)
      (*i)();
  }

  void operator ()()
  {
    Call();
  }

  Signaler& operator*=(Func f)
  {
    _postHandlers.push_back( f );
    return *this;
  }

  Signaler& operator/=(Func f)
  {
    for(auto i = _postHandlers.begin(); i != _postHandlers.end(); i++)
    {
      if ( (*i).template target<void (void)>() == f.template target<void (void)>() )
      {
        _postHandlers.erase( i );
        break;
      }
    }

    return *this;
  }

  Signaler& operator+=(Func f)
  {
    _handlers.push_back( f );
    return *this;
  }

  Signaler& operator-=(Func f)
  {
    for(auto i = _handlers.begin(); i != _handlers.end(); i++)
    {
      if ( (*i).template target<void (void)>() == f.template target<void (void)>() )
      {
        _handlers.erase( i );
        break;
      }
    }

    return *this;
  }

  bool IsRegistered(Func f)
  {
    for(auto i = _handlers.begin(); i != _handlers.end(); i++)
      if ( (*i).template target<void (void)>() == f.template target<void (void)>() )
        true;

    return false;
  }

private:
  std::vector<Func> _handlers;     // First step handlers
  std::vector<Func> _postHandlers; // Second step handlers
};

#pragma endregion

}

Notices that I have also try the following definition :

template<typename T1, typename T2=void> class Signaler
{ ... }

template<typename T1> class Signaler<T1,void>
{ ... }

template<> class Signaler<void,void>
{ ... }

But I got a "LINK" error :

error LNK2001: unresolved external symbol "public: static class Signaler ShadingSystem::Signal_ShaderUpdated" (?Signal_ShaderUpdated@ShadingSystem@2V?$Signaler@PEAVShader@@@spectralCore@@A) D:\\spectralGraph.lib(VNScene.obj)

From this question , it seems that templates cannot be overloaded on their number of arguments in C++98. However, you can use the suggested trick where you define the base template as having the maximum number of supported template arguments and then have specializations when the tail template arguments are void. If you combine this with the repeated header inclusion with macro expansion trick, you get something like this:

Signaler.h:

#include <functional>
#include <vector>

template<typename T1 = void, typename T2 = void, typename T3 = void, typename T4 = void, typename T5 = void>
class Signaler
{
private:
  Signaler();
};

#define SIGNALER_EXPAND_TYPES(macro) 
#include "SignalerSpecialization.h"
#undef SIGNALER_EXPAND_TYPES

#define SIGNALER_EXPAND_TYPES(macro) macro(T1)
#include "SignalerSpecialization.h"
#undef SIGNALER_EXPAND_TYPES

#define SIGNALER_EXPAND_TYPES(macro) macro(T1), macro(T2)
#include "SignalerSpecialization.h"
#undef SIGNALER_EXPAND_TYPES

// Same for 3, 4 and 5 args

SignalerSpecialization.h:

#define SIGNALER_EXPAND_TYPE(T) T
#define SIGNALER_TYPE_LIST SIGNALER_EXPAND_TYPES(SIGNALER_EXPAND_TYPE)

#define SIGNALER_EXPAND_TEMPLATE_ARGUMENT(T) typename T
#define SIGNALER_TEMPLATE_ARGUMENT_LIST SIGNALER_EXPAND_TYPES(SIGNALER_EXPAND_TEMPLATE_ARGUMENT)

#define SIGNALER_EXPAND_PARAMETER(T) T arg##T
#define SIGNALER_PARAMETER_LIST SIGNALER_EXPAND_TYPES(SIGNALER_EXPAND_PARAMETER)

#define SIGNALER_EXPAND_ARGUMENT(T) arg##T
#define SIGNALER_ARGUMENT_LIST SIGNALER_EXPAND_TYPES(SIGNALER_EXPAND_ARGUMENT)

template<SIGNALER_TEMPLATE_ARGUMENT_LIST>
class Signaler<SIGNALER_TYPE_LIST>
{
private:
  typedef std::function<void (SIGNALER_TYPE_LIST)> Func;

public:
  void Call(SIGNALER_PARAMETER_LIST)
  {
    for(auto i = _handlers.begin(); i != _handlers.end(); i++)
      (*i)(SIGNALER_ARGUMENT_LIST);

    for(auto i = _postHandlers.begin(); i != _postHandlers.end(); i++)
      (*i)(SIGNALER_ARGUMENT_LIST);
  }

  void operator()(SIGNALER_PARAMETER_LIST)
  {
    Call(SIGNALER_ARGUMENT_LIST);
  }

  Signaler& operator*=(Func f)
  {
    _postHandlers.push_back(f);
    return *this;
  }

  Signaler& operator/=(Func f)
  {
    for(auto i = _postHandlers.begin(); i != _postHandlers.end(); i++)
    {
      if ((*i).template target<Func>() == f.template target<Func>())
      {
        _postHandlers.erase(i);
        break;
      }
    }

    return *this;
  }

  Signaler& operator+=(Func f)
  {
    _handlers.push_back(f);
    return *this;
  }

  Signaler& operator-=(Func f)
  {
    for(auto i = _handlers.begin(); i != _handlers.end(); i++)
    {
      if ((*i).template target<void (SIGNALER_TYPE_LIST)>() == f.template target<void (SIGNALER_TYPE_LIST)>())
      {
        _handlers.erase(i);
        break;
      }
    }

    return *this;
  }

  bool IsRegistered(Func f)
  {
    for(auto i = _handlers.begin(); i != _handlers.end(); i++)
      if ((*i).template target<void (SIGNALER_TYPE_LIST)>() == f.template target<void (SIGNALER_TYPE_LIST)>() )
        true;

    return false;
  }

private:
  std::vector<Func> _handlers;     // First step handlers
  std::vector<Func> _postHandlers; // Second step handlers
};

#undef SIGNALER_EXPAND_TYPE
#undef SIGNALER_TYPE_LIST

#undef SIGNALER_EXPAND_TEMPLATE_ARGUMENT
#undef SIGNALER_TEMPLATE_ARGUMENT_LIST

#undef SIGNALER_EXPAND_PARAMETER
#undef SIGNALER_PARAMETER_LIST

#undef SIGNALER_EXPAND_ARGUMENT
#undef SIGNALER_ARGUMENT_LIST

PS: Your overloading of the *= and /= operators is of very poor taste.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM