2016-12-05 1 views
1

Я хочу, чтобы операция «лучше» выполнялась для указателя на метод.Помощник листинга для перегруженного указателя функции элемента

Предоставлен класс с перегруженными функциями-членами и шаблоном, который ест каждый тип указателей и объектов элемента и просто вызывает их.

class A 
{ 
    public: 
     void Do(int i) { std::cout << "Hallo with int " << i << std::endl;} 
     void Do(float f) { std::cout << "and with float " << f << std::endl;} 
     void Do(std::string s) { std::cout << "also with string " << s << std::endl;} 
}; 

    template <typename OBJECT, typename METHOD, typename ... PARMS> 
void Call(OBJECT& obj, METHOD m, PARMS ... parms) 
{ 
    std::cout << __PRETTY_FUNCTION__ << std::endl; 

    (obj.*m)(parms...); 
} 

Теперь, если я хочу использовать Call шаблон, я должен вручную привести указатель, чтобы получить правильную версию перегруженных функций, как:

Call(a, static_cast< void(A::*)(int)>(&A::Do), 1); 
    Call(a, static_cast< void(A::*)(float)>(&A::Do), 8.88); 
    Call(a, static_cast< void(A::*)(std::string)>(&A::Do), "Willi"); 

Так что я хотел бы сделать отбрасывать немного легче читать и получил этот вспомогательный класс:

template <typename > class Cast; 

template < typename RET, typename ... ARGS > 
class Cast< RET(ARGS...)> 
{ 
    public: 
     template < typename OBJ > 
      static auto From(RET(OBJ::*ptr)(ARGS...))-> RET(OBJ::*)(ARGS...) 
      { 
       return ptr; 
      } 
}; 

и может использовать его как:

Call(a, Cast<void(int)>::From(&A::Do), 100); 
    Call(a, Cast<void(float)>::From(&A::Do), 4.46); 
    Call(a, Cast<void(std::string)>::From(&A::Do),"Check it"); 

Вопрос: Возможно ли сделать мой класс Cast функцией шаблона, чтобы получить синтаксис для приведения вызова немного проще? Я хочу что-то, что можно назвать так:

Call(a, Cast<void(std::string)>( &A::Do), "Yeeeaaa!"); 

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

Разрешены любые виды C++. Если C++ 17 дает новый способ, дайте мне знать!

Почему я не могу использовать параметры для лямбда внутри вызова функции:

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

Register(a, Cast<void(int)>::From(&A::Do)); 

ответ

2

Вам не нужно выделять аргументы и тип результата только для их объединения. Просто объявить указатель члена для типа функции:

template <typename F, typename C> 
auto Cast(F (C::*ptr)) { 
    return ptr;  
} 

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

Call(a, Cast<void(std::string)>(&A::Do), "Yeeeaaa!"); 
+0

Я никогда не видел такой синтаксис раньше! Он работает отлично, но можете ли вы объяснить, что делает «Cast» (F (C :: * ptr))? Я не могу заменить: 'Cast (void (int) C :: *)', если F не является параметром шаблона. Поэтому я смущен этой синтаксической формой. – Klaus

+1

Нет, это точно, что происходит. C++ просто не позволяет вам прямо писать композитный тип там, например, вы не можете объявить массив с помощью 'int [42] a;', но вы можете сделать 'using A = int [42]; A a; 'То же самое здесь:' используя F = void (int); auto Cast (F C :: *) {} 'делает то, что вы ожидаете. –

+1

@ Klaus, это не указатель на функцию! Это общий указатель на член, любой его член. Итак, когда вы вызываете это так, вы даете ему указатель на член, имеющий тип 'void (std :: string)'. Снова - обратите внимание, нет второго набора parenthethis. Может быть, это будет более ясно, если писать без скобок вообще: 'auto Cast (F C :: * ptr)' - тот же результат. – SergeyA

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