如何将模板名称传递给方法?

时间:2017-04-19 17:52:54

标签: c++ templates

假设我有两个用于迭代容器的模板函数:

template <typename I, typename C>
It Prev(I i, const C& c) noexcept {
    Expects(i != c.end());
    if (i == c.begin()) return c.end();
    return i - 1;
}

template <typename I, typename C>
It Next(I i, const C& c) noexcept {
    Expects(i != c.end());
    return i + 1;
}

具有使用这些模板的GetNextElement和GetPrevElement的类:

struct MyClass {
  std::vector<int> elements;

  int* GetNextElement(std::vector<int>::iterator i) {
    auto next = Next(i, elements);
    if (next == elements.end()) return nullptr;
    return &*it;
  }
  int* GetPrevElement(std::vector<int>::iterator i) {
    auto prev = Prev(i, elements);
    if (prev == elements.end()) return nullptr;
    return &*it;
  }
};

除了调用不同的模板外,这两种方法的功能相同。如何将这些转换为可能被称为

的单个成员函数
MyClass mc;
// ...
auto it = mc.elements.begin();
auto next = mc.GetElement<Next>(it);
// Or maybe mc.GetElement(it, Next);

3 个答案:

答案 0 :(得分:2)

#define OINVOKE(...) __VA_ARGS__(decltype(args)(args)...)
#define OVERLOADS_OF(...) [](auto&&...args)\
    noexcept(noexcept(OINVOKE(__VA_ARGS__)))\
    ->decltype(OINVOKE(__VA_ARGS__))\
    { return OINVOKE(__VA_ARGS__); }

auto fNext=OVERLOADS_OF(Next);
auto fPrev=OVERLOADS_OF(Prev);

然后:

template<auto* pf>
int* GetElement(std::vector<int>::iterator i) {
  auto next = (*pf)(i, elements);
  if (next == elements.end()) return nullptr;
  return &*it;
}
auto it = mc.elements.begin();
auto next = GetElement<&fNext>(it);

需要C ++ 17。

答案 1 :(得分:1)

如果您可以将函数包装在struct中,则会大大简化此问题。

struct Prev
{
    template <typename I, typename C>
    I operator()(I i, const C& c) noexcept {
        Expects(i != c.end());
        if (i == c.begin()) return c.end();
        return i - 1;
    }
};

struct Next
{
    template <typename I, typename C>
    I operator()(I i, const C& c) noexcept {
        Expects(i != c.end());
        return i + 1;
    }
};

然后,您可以将它们作为模板参数传递。

struct MyClass 
{
public:
    auto begin() { return elements.begin(); }
    auto end() { return elements.end(); }

    template<typename T, typename I>
    I GetElement(I iter)
    {
        return T()(iter, this->elements);
    }

private:
    std::vector<int> elements;
};

int main()
{
    MyClass mc;
    auto it = mc.begin();
    auto next = mc.GetElement<Next>(it);
    auto prev = mc.GetElement<Prev>(it);
}

答案 2 :(得分:0)

您可以尝试以下代码:

template <std::vector<int>::iterator (*FOO)(std::vector<int>::iterator, const std::vector<int>&)>
std::vector<int>::iterator GetElement(std::vector<int>::iterator i)
{
     return FOO(i, elements);
}