2013-06-27 8 views
2

Представьте себе класс (в VS2010, не VARIADIC шаблоны здесь извините)Условная компиляция перегруженных функций в шаблонных классов

template <class Arg> 
class FunctionWrapper 
{ 
public: 
     void Invoke(Arg arg){_fn(arg)}; 
private: 
     std::function<void(Arg)> _fn; 
} 

я не могу сделать то, например,

FunctionWrapper <int> foo; foo.Invoke(4); 

И это компилируется в порядке. Но это не так:

FunctionWrapper <void> foo; foo.Invoke(); 

Теперь я мог бы обойти это, используя специализированную специализацию. Но я также задавался вопросом, есть ли способ, которым я мог бы обойти это еще один способ ....

template <class Arg> 
class FunctionWrapper 
{ 
public: 
     void Invoke(void){_fn()};     // } overloaded 
     void Invoke(Arg arg){_fn(arg)};    // } 
private: 
     std::function<void(Arg)> _fn; 
} 

т.е. перегрузки Invoke, а затем ответить на условной компиляции, так что если я создаю экземпляр FunctionWrapper<void>, версии Invoke с аргументом никогда не компилируется. Я уверен, что я читал, как это сделать в Modern C++, но я не могу запомнить подробности .....

+0

Я думал, что это идеальный сценарий для использования специализации. Даже если то, что вы спросите, может быть сделано, какая польза? –

+0

A. Мне интересно, как это сделать, поскольку я думаю, что это возможно, и мне нравится знать. B. Это избавит меня от определения второго, в основном идентичного определения класса для специализации void. –

ответ

0

Если вы пытались реализовать функтор таким образом, было бы несколько очевидных недостатков в дизайне; Я предполагаю, и вы, похоже, четко прокомментируете комментарии, что код просто, ну, пример, используемый для формулировки вашего дела.

Вот несколько решений проблемы:

template<class T> 
struct Trait{ 
    typedef T type; 
    typedef T mock_type; 
}; 
template<> 
struct Trait<void>{ 
    typedef void type; 
    typedef int mock_type; 
}; 

template <class Arg> 
class FunctionWrapper 
{ 
public: 
     void Invoke(void){_fn();} 
     void Invoke(typename Trait<Arg>::mock_type arg){_fn(arg);} 
     boost::function<void(typename Trait<Arg>::type)> _fn; 
private: 
}; 

template <class Arg> 
class FunctionWrapper2 
{ 
public: 
    FunctionWrapper2(const boost::function<void(Arg)> arg) : Invoke(arg){} 
    const boost::function<void(Arg)> Invoke; 
}; 

int main(int argc, _TCHAR* argv[]) 
{ 

    FunctionWrapper<int> cobi; 
    cobi._fn = &countOnBits<int>; 
    cobi.Invoke(5); 

    FunctionWrapper<void> cobv; 
    cobv._fn = &func; 
    cobv.Invoke(); 

    FunctionWrapper2<int> cobi2(&countOnBits<int>); 
    cobi2.Invoke(5); 

    FunctionWrapper2<void> cobv2(&func); 
    cobv2.Invoke(); 
    //[...] 
} 

Конечно, я не говорю, что то, что я написал хороший код, как для вопроса оно предназначено только привести примеры рабочих конструкций ,

Проблема с вашей попыткой заключается в том, что, хотя функция void Invoke (Arg arg) {_ fn (arg)}; на самом деле не компилируется, когда вы инициируете FunctionWrapper (и не делаете попыток вызвать функцию Invoke с параметром), она синтаксически проверяется; и, конечно, Invoke (void arg) - это не то, что ваш компилятор собирается принять!

Это мой первый ответ на stackoverflow, я надеюсь, что у меня все было в порядке; если нет, пожалуйста, дайте мне некоторую обратную связь и не слишком расстраивайтесь :)