Why member functions can't be used as template arguments?

隐身守侯 提交于 2019-12-30 08:29:34

问题


Why member functions cannot be used as template arguments? For example, I want to do like:

struct Foo {
    void Bar() { // do something
    }
};
template <typename TOwner, void(&func)()>
void Call(TOwner *p) {
    p->func();
}
int main() {
    Foo a;
    Call<Foo, Foo::Bar>(&a);
    return 0;
}

I know that a similar thing can be done using pointers-to-member; well, it's cool enough most of the time, but I'm just curious about why pointers "should" be used.

I see no ambiguity of interpreting "p->func()" above. Why the standard prohibits us to use member functions as template arguments? Even static member functions are not allowed according to my compiler (VC++ 2013). Does anyone know the reason? Or, is there a way to do the same thing without loss of any performance due to pointer dereferencing?

Thank you.


回答1:


They can be used as non-type parameters, but you need to use the right syntax

struct Foo {
    void Bar() { // do something
    }
};
template <typename TOwner, void(TOwner::*func)()>
void Call(TOwner *p) {
    (p->*func)();
}
int main() {
    Foo a;
    Call<Foo, &Foo::Bar>(&a);
    return 0;
}



回答2:


In fact, member-function pointers can be used as template arguments (just exactly as any other pointer type may be used as template parameter):

struct A
{
    int f(float x);
};

template <int (A::F*)(float)>
struct B {};

template<A *> struct C;
template<A &> struct D;

However, according to the following excerpt from the C++ standard, one cannot pass references to members.

[temp.param]

  1. A non-type template-parameter shall have one of the following (optionally cv-qualified) types:

(4.1) — integral or enumeration type,

(4.2) — pointer to object or pointer to function,

(4.3) — lvalue reference to object or lvalue reference to function,

(4.4) — pointer to member,

(4.5) — std::nullptr_t.



Next, given you managed to pass your function type somehow and want to call it inside, you encounter the same problem as if you want to store them inside a function pointer or a std::function object: namely to call you need both, the member function as well as the concrete object. Passing only the function won't suffice.

But in fact you can achieve what you want. Just bind the function to your object and pass it afterwards:

template<typename T, typename F>
void call(T&& t, F&&f)
{
    f(std::forward<T>(t));
}

struct A
{
    void foo() { std::cout<<"hello"<<std::endl; }  
};

int main()
{
    A a;
    auto f=std::bind(&A::foo, a);   //or possibly "std::ref(a)" instead of "a"
    call(3,f);
}

DEMO



来源:https://stackoverflow.com/questions/30930350/why-member-functions-cant-be-used-as-template-arguments

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!