简体   繁体   English

Visual Studio 2012:没有可变参数模板:解决方案?

[英]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. 我有一个需要支持动态类型参数集的类,但是VS2012不支持可变参数模板。 (VS2013 and the compiler CTP do support variadic templates, but I can't use them. Nor can I use Boost.) (VS2013和编译器CTP 确实支持可变参数模板,但我不能使用它们。也不能使用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.) (请注意,如果您通过Signaler重命名Signaler2,则存在一些编译问题。)

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 : 但是我收到一个“ LINK”错误:

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) 错误LNK2001:无法解析的外部符号“公共:静态类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. 这个问题来看,似乎模板不能在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: 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: 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. PS:* =和/ =运算符的重载很不好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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