2015-10-17 3 views
2
template<typename Signature> 
class myfunction //basic class template 
{ 
}; 

template<typename R, typename... Args> 
class myfunction<R (Args...)> //normal function specialized edition 
{ 
    typedef R (*Ptr)(Args...); 
    Ptr m_p; 
public: 
myfunction(Ptr p) : m_p(p) 
{ 

} 
R operator()(Args... args) 
{ 
    return m_p(args...); 
} 
}; 

template<typename R, typename T, typename ... Args> 
class myfunction<R (T*, Args...)> //member function specialized edition one 
{ 
    typedef R (T::* mPtr)(Args...); 
    mPtr m_p; 
public: 
    myfunction(mPtr p): m_p(p) 
    { 

    } 
    R operator()(T* likeThis, Args...args) 
    { 
     return (likeThis->*m_p)(args...); 
    } 
}; 


template<typename R, typename T, typename ... Args> 
class myfunction<R (T, Args...)> //member function specialized edition two 
{ 
    typedef R (T::* mPtr)(Args...); 
    mPtr m_p; 
public: 
    myfunction(mPtr p): m_p(p) 
    { 

    } 
    R operator()(T likeThis, Args...args) 
    { 
     return (likeThis.*m_p)(args...); 
    } 
}; 

template<typename R, typename T, typename ... Args> 
class myfunction<R(T&, Args...)> //member function specialized edition three 
{ 
    typedef R (T::* mPtr)(Args...); 
    mPtr m_p; 
public: 
    myfunction(mPtr p): m_p(p) 
    { 

    } 
    R operator()(T& likeThis, Args...args) 
    { 
    return (likeThis.*m_p)(args...); 
    } 
}; 

int func1() 
{ 
    cout << "func1"; 
    return 0; 
    } 

void func2(int x) 
{ 
    cout << "func2"; 
    cout << x ; 
} 
int main() 
{ 
    myfunction<int(void)> f1(func1); 
    f1(); 
    myfunction<void(int)> f2(func2);//this will fail, why? 
    f2(1); 
    return 0; 
} 

Я хочу смягчить функцию обертки в стандартной библиотеке. Тест-код аналогичен приведенному выше. Тем не менее, f1 может считать правильное, это стандартная специализированная редакция. В то время как f2 сначала соответствует специальной функции-члене, но после неудачи сопоставления, она должна идти в соответствие с обычной специализированной редакцией, а затем преуспеть? Это именно то, что означает SFINAE, верно? После того, как я прокомментирую функцию-член, специализированную редакцию второй, она соответствует одной воле, почему? , пожалуйста, помогите мне.Выбор шаблона и SFINAE?

+0

Проблема заключается в том, что ваши специализации специализированы для обычной функции с хотя бы одним аргументом, а не с функциями-членами. Измените специализацию на нечто вроде 'template stuct Foo ;'. Также имейте в виду, что cv квалифицированные функции или функции члена с различными соглашениями о вызовах имеют разные подписи. –

+0

Хорошо, спасибо за ваш ответ. Я знаю, что это может работать: template class myfunction .when я хочу обернуть класс функций-членов Myclass { public: int f (int x) { cout << "функция-член!" << x << endl; return 0; } }; Я должен написать вот так: Myclass obj; myfunction f3 (& Myclass :: f); f3 (obj, 3); Я хочу сохранить последовательность и написать как myfunction f3 (& Myclass :: f); как я могу это сделать :? –

ответ

0

Как указано в комментариях - это специализация берет на ваших один ARG свободных функций:

template<typename R, typename T, typename ... Args> 
class myfunction<R (T, Args...)> //member function specialized edition two 
{ 
    typedef R (T::* mPtr)(Args...); 
    mPtr m_p; 
public: 
    myfunction(mPtr p): m_p(p) 
    { 

    } 
    R operator()(T likeThis, Args...args) 
    { 
     return (likeThis.*m_p)(args...); 
    } 
}; 

Easy ответ просто удалить эту специализацию и ваша программа запуска компиляции.

Но - std::function Реализация не так проста, как вы могли бы ожидать. Вам нужно использовать технику type erasure для подражания ее поведению - я имею в виду, что myFunction<R(Arg...> на уровне myFunction должен служить для всех бесплатных функций и функций-членов - только при построении конкретного экземпляра объекта вы должны выбрать «реализацию» через тип аргумента - если это функция-член или свободная функция.

Сначала вы должны определить любой вызов функции абстракции:

template<typename R, typename T, typename ... Args> 
class AnyFunctionCall 
{ 
public: 
    virtual ~AnyFunctionCall() {} 

    virtual R call(T arg, Arg&&... args) const = 0; 
}; 

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

template<typename R, typename T, typename ... Args> 
class myfunction<R (T, Args...)> 
{ 
    std::unique_ptr<AnyFunctionCall> implementation; 

public: 
    template <typename Functor> 
    myfunction(Functor p): m_p(makeFunctionCall(std::forward<Functor>(p))) 
    { 

    } 
    R operator()(T arg, Arg&&... args) 
    { 
     return implementation->call(arg, args...); 
    } 
}; 

Вы видите - требуется иметь один аргумент (объект или первый аргумент свободной функции). Для функции нулевого аргумента у вас может быть ваша простая специализация для бесплатной функции myfunction<R()>.

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