是否可以获得一个模板来使用一个类和该类的成员函数?

Posted

技术标签:

【中文标题】是否可以获得一个模板来使用一个类和该类的成员函数?【英文标题】:Is it possible to get a template to use a class and a member function of that class? 【发布时间】:2015-02-25 17:02:39 【问题描述】:

我正在尝试为使用大小函数和项目索引函数的通用对象创建for_each 函数。但是我在语法上遇到了一些困难。

这是我目前所拥有的(从第 128 行开始):

class base1

protected:
    std::vector<int> items;
public:
    base1()
        : items(1,2,3)
    
    

    int GetCount() const
    
    
;

class base2 : public base1

public:
    base2()
        : base1()
    
    

    int GetItem(int i) const
    
        return items[i];
    
;

class derived : public base2

public:
    derived()
        : base2()
    
    
;

template <typename CONTAINER, typename CONTAINER_BASE1, typename CONTAINER_BASE2, typename SIZE, typename CONTAINED, typename FUNC>
void for_each(CONTAINER* container, SIZE (CONTAINER_BASE1::*GetSize)() const, CONTAINED (CONTAINER_BASE2::*GetItem)(SIZE) const, FUNC& body)

    for (SIZE i = 0; i < container->*GetSize(); ++i)
    
        body(container->*GetItem(i));
    


void fn()

    derived x;
    for_each(&x, &derived::GetCount, &derived::GetItem, [](int i)
        ++i;
    );

现在,我收到来自 VC++ 2013 的错误说明:

1>d:\projects\test\test.cpp(169): error C2064: term does not evaluate to a function taking 0 arguments
1>          d:\projects\test\test.cpp(180) : see reference to function template instantiation 'void for_each<derived,base1,base2,int,int,fn::<lambda_862ea397905775f7e094cde6fe9b462c>>(CONTAINER *,SIZE (__thiscall base1::* )(void) const,CONTAINED (__thiscall base2::* )(SIZE) const,FUNC &)' being compiled
1>          with
1>          [
1>              CONTAINER=derived
1>  ,            SIZE=int
1>  ,            CONTAINED=int
1>  ,            FUNC=fn::<lambda_862ea397905775f7e094cde6fe9b462c>
1>          ]
1>d:\projects\test\test.cpp(171): error C2064: term does not evaluate to a function taking 1 arguments

关于问题所在有什么想法吗?

【问题讨论】:

【参考方案1】:

你有两个错误。您通过非常量左值引用获取函子 - FUNC&amp; body - 它不会像 lambda 那样绑定到临时值;这被允许此类绑定的可怕 MSVC 扩展隐藏了。您应该按值(通常由标准库完成的方式)、通过 const 左值引用(如果复制代价高昂和/或身份很重要)或转发引用(如果身份很重要并且 @987654322 @ 可以是非const)。

其次是运算符优先级。后缀函数调用运算符的优先级高于.*-&gt;*container-&gt;*GetSize()container-&gt;*(GetSize());你想要(container-&gt;*GetSize)()

我也不确定这个设计。提供一个统一的接口,并简单地做,例如container.size()container.at(i),可能比使用这种折磨人的指向成员函数的系统更好。

【讨论】:

哦,那不是很好。 :) 但我不是这个图书馆的制造者。 base1base2derived 仅用于此处,不用于实际生产。谢谢。 顺便说一句,您指的 MSVC 扩展是什么?我应该只使用FUNC body 而不是FUNC const &amp; body 吗?似乎与我使用FUNC&amp; body 制作的另一个作品合作过。 @Adrian MSVC 允许非常量左值引用绑定到临时对象。标准库的风格是按值传递函子,但你也可以使用const FUNC&amp;FUNC&amp;&amp;(转发参考)。 啊,很高兴知道。但是,前向参考的意义是什么?我到底要搬什么? @Adrian 当你想同时接受左值和右值,但身份很重要(所以不能通过值复制/传递),并且仿函数的operator() 可以是非常量(所以不能通过 const 引用)。 std::shuffle 是一个例子 - 它通过转发引用获取其 RNG。在这种情况下,它并没有真正用于转发; Scott Meyers 的旧“通用参考”术语可能更合适。

以上是关于是否可以获得一个模板来使用一个类和该类的成员函数?的主要内容,如果未能解决你的问题,请参考以下文章

类和对象之友元

03_11_对象转型

static为什么能和final一起来使用?

C++模板编程中只特化模板类的一个成员函数(花样特化一个成员函数)

类和对象之模板

面向对象