0

У меня есть класс, который должен поддерживать динамический набор аргументов типа, но VS2012 не поддерживает вариационные шаблоны. (VS2013 и компилятор CTP сделать поддержку VARIADIC шаблоны, но я не могу их использовать. Не могу я использовать Boost.)Visual Studio 2012: нет вариационных шаблонов: решение?

Итак, я пытаюсь найти решение, используя «шаблоны специализации». Ниже я до сих пор. (Обратите внимание, что если вы переименуете Signaler2 Signaler ... есть некоторые проблемы с компиляцией.)

Любые идеи о том, как решить эту проблему?

#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 

} 

Извещения, что я также попробовать следующее определение:

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

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

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

Но я получил "LINK" ошибка:

ошибка LNK2001: неразрешенный внешний символ «общественности: статический класс сигнализатора ShadingSystem :: Signal_ShaderUpdated»(Signal_ShaderUpdated @ ShadingSystem @ 2V $ сигнализатора @ PEAVShader @@@ spectralCore @@?) D: \ spectralGraph.lib (VNScene.obj)

+0

То, что Microsoft использовала для имитации вариационных шаблонов в STL, заключалось в том, чтобы включать один и тот же заголовок несколько раз с некоторыми макросами, определенными по-разному, чтобы он расширялся в шаблоны с различным количеством аргументов. Это уродливо, но вы можете использовать тот же трюк. – Trillian

+0

Спасибо. Конечно, это способ сделать. Но сначала я должен уметь определять это вручную ... это то, что я пытаюсь сделать прямо сейчас! Как только у меня будет этот компилятор кода ... Я смогу работать над макросом ;-) – Spectral

+1

Я не думаю, что строка '(* i) .template target () == f .template target () 'делает то, что вы думаете. Вы не можете проверить 'std :: function' за равенство в том, как вы его используете - вам нужны отдельные маркеры. – Xeo

ответ

1

От this question, похоже, что шаблоны не могут быть перегружены по количеству аргументов в C++ 98. Однако вы можете использовать предлагаемый трюк, в котором вы определяете базовый шаблон как имеющее максимальное количество поддерживаемых аргументов шаблона, а затем имеете специализации, когда аргументы шаблона хвоста недействительны. Если объединить это с включением повторного заголовка с макро-трик расширения, вы получите что-то вроде этого:

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: Ваш перегружать операторов * = и/= имеет очень плохой вкус.

+0

Привет, Я попробовал другое определение (см. Вопрос, пожалуйста), но у меня возникла ошибка LINK! У кого-то есть идея решить проблему? Thx – Spectral

+0

BTW, Trillian, ваш пример не скомпилирован: '( – Spectral

+0

@Spectral К сожалению, в нем отсутствует STL #includes, теперь он должен работать. Что касается вашей ошибки связи, это касается вашего класса ShadingSystem, а не класса Signaler. – Trillian

Смежные вопросы