将重载成员函数传递给函数模板

时间:2018-11-01 15:30:17

标签: c++ c++14 c++17 template-meta-programming

我想拥有一个函数,该函数使用提供的可变参数输入参数调用给定的成员函数。我写了这样的东西:

#include <type_traits>
#include <utility>    

struct A {
    constexpr int show(int a, int b) const noexcept {return a + b;}
};

template <typename T, typename MemFn, typename ... Args>
int show(T && obj, MemFn Fn, Args&&... args)
{
    return (obj.*Fn)(std::forward<Args>(args)...);
}

int main()
{
    constexpr A a;
    return show(a, &A::show, 1, 2);
}

,只要我在结构中只有show方法的一个定义,它就可以正常工作。一旦我添加类似

struct A {
    constexpr int show(int a, int b) const noexcept {return a + b;}
    constexpr int show(int a) const noexcept {return a * 3;}
};

编译器无法推断出成员函数的类型,这确实很有意义,但是我想知道是否存在针对此问题的解决方法,例如将输入参数类型嵌入成员函数模板中? >

可以找到示例代码here

3 个答案:

答案 0 :(得分:4)

这是一个令人烦恼的难题,不断提出语言建议以试图解决(React - Uncaught TypeError: Cannot read property 'func' of undefinedUncaught TypeError: Cannot read property 'func' of undefinedP0119)。

直到那时,如何包装在类型上调用特定成员函数的问题非常困难,在该类型中,该成员函数要么是重载的,要么是模板,或者是采用默认参数的。

最简单的方法是编写一个lambda:

vector<int> method(const vector<int> &vec,int value) {
  vector<int> newvec;
  bool done {false};
  int i = vec.size()-1;
  while (!done && i >= 0) {
    if (value >= vec.at(i)) {
        value -= vec.at(i);
        newvec.push_back(i);
    } 
    if (value == 0) {
        cout << "done" << endl;
        done = true;
    } else {
        --i;
    }
  }
  return newvec;
}

但这实际上不是那么容易,也不是特别方便-实际上,它只能处理[](A& a, auto&&... args) -> decltype(a.show(FWD(args)...)) { return a.show(FWD(args)...); } 可在非show const上调用的情况。如果我们有A和非const重载怎么办?还是const&

我认为,最完整的实现方式是将P0834P1170结合使用:

&&

根据您的情况,您需要:#define CLASS_MEMBER(T, mem) boost::hof::fix(boost::hof::first_of(\ boost::hof::match( \ [](auto, T& s, auto&&... args) \ BOOST_HOF_RETURNS(s.mem(FWD(args)...)), \ [](auto, T&& s, auto&&... args) \ BOOST_HOF_RETURNS(std::move(s).mem(FWD(args)...)), \ [](auto, T const&& s, auto&&... args) \ BOOST_HOF_RETURNS(std::move(s).mem(FWD(args)...)), \ [](auto, T const& s, auto&&... args) \ BOOST_HOF_RETURNS(s.mem(FWD(args)...))), \ [](auto self, auto&& this_, auto&&... args) \ BOOST_HOF_RETURNS(self(*FWD(this_), FWD(args)...)) \ )) 。这将为您提供一个可以正确调用的函数对象:

CLASS_MEMBER(A, show)

答案 1 :(得分:1)

  

我想知道是否有解决此问题的方法,例如将输入参数类型嵌入成员函数模板中?

使用lambda代替对象和成员函数指针。例如:

struct A {
    constexpr int show(int a, int b) const noexcept {return a + b;}
    constexpr int show(int a) const noexcept {return a * 3;}
};

template <typename F, typename ... Args>
int show(F&& f, Args&&... args) {
    return std::forward<F>(f)(std::forward<Args>(args)...);
}

int main() {
    constexpr A a;
    auto f = [&a](auto... args) { return a.show(std::forward<decltype(args)>(args)...); };
    show(f, 1);
    show(f, 1, 2);
}

答案 2 :(得分:0)

您可以使用更具体的成员函数类型来约束函数:

template <typename T, typename... Args>
int show(T && obj, int(std::remove_reference_t<T>::*Fn)(int, int) const, Args&&... args)
{
    return (obj.*Fn)(std::forward<Args>(args)...);
}

但是,根据您的用例,此定义可能会受到限制,因为现在Fn参数必须与int(int, int) const签名完全匹配,包括可能的cv和ref限定词。