2017-04-19 29 views
1

可以说我有两个模板功能,通过一个容器的遍历:如何将模板名称传递给方法?

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); 
+0

'Next'和'Prev'期待与迭代器相关联的容器的引用。 'GetElement'不知道容器。既然你似乎在使用'std :: vector :: iterator's,我没有看到如何实现这一点。您将需要将容器传递给'GetElement'或从'Next'和'Prev'删除该需求。 –

+0

你还没有定义'期望'是什么。您使用'It'作为'Prev'和'Next'的返回类型类型,但它是未声明的。看起来你打算使用'I'类型。 –

+0

我可能在我的例子中简化了太多,并且暴露了调用者不会意识到的事情。调用者不知道元素如何存储在课堂中。他只知道他可以获取元素的标识符,并且可以调用“GetNextElement”或“GetPrevElement”。由于这两个方法几乎完全相同,我希望能够拥有一个方法,并让调用方指定是否应使用Next或Prev模板函数来获取所需的元素。 – Kian

回答

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); 
} 
+0

调用者不能访问mc.elements本身(它是私有的),所以一个免费函数将无济于事。我只是把它暴露出来以简化这个例子。我希望调用者能够告诉方法使用Next或Prev,但不知道使用什么类型来实例化它。 – Kian

+0

在您的示例中,GetElement 无法知道要使用哪个“mc”或“mc.element”实例。你想让'GetElement '成为'MyClass'的成员方法吗? –

+0

啊,我刚刚注意到了。是的,GetElement试图成为一个成员,取代了两个GetPrevElement和GetNextElement方法。我修正了错字。抱歉。所以编辑并没有真正解决问题,因为它调用了两个成员而不是替换它们。 – Kian

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。

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); 
} 
相关问题