如何从构造函数传递给作为成员函数的谓词

时间:2014-01-04 17:48:16

标签: c++ sorting pointers constructor

我有以下代码:

template <class T>
class GenericGeneticSolver
{
public:
    GenericGeneticSolver(IGenticSolverHelper<T>& helper, int generationSize) : mSolverHelper(helper), mGenerationSize(generationSize)
    {
        mCurrentGeneration.resize(mGenerationSize);
        for(int i=0;i<mGenerationSize;i++)
        {
            mSolverHelper.GenerateRandomSolution(mCurrentGeneration[i]);
        }

        sort(mCurrentGeneration.begin(),mCurrentGeneration.end(), solutionComparer);
    }
    void Evolve(int numberOfGenerations = 1)
    {
        //sort(mCurrentGeneration.begin(),mCurrentGeneration.end(), solutionComparer);
    }
private :
    int mGenerationSize;
    vector<T> mCurrentGeneration;
    IGenticSolverHelper<T>& mSolverHelper;

    bool solutionComparer (T first,T second) { return (mSolverHelper.Cost(first)<mSolverHelper.Cost(second)); }
};

constructor我正在用成员填充向量,然后我试图通过将谓词传递给Sort函数来对该向量进行排序,谓词是一个名为`的成员函数solutionComparer。

不幸的是它没有编译,编译器不满意在构造函数中使用指向成员函数的指针,我在“Evolve”函数中尝试了相同的行,并且它确实编译。

我得到的错误是:

error C3867: 'GenericGeneticSolver<T>::solutionComparer': function call missing argument list; use '&GenericGeneticSolver<T>::solutionComparer' to create a pointer to member

我试图做错误建议的但是它也没有编译(sort函数中的一些随机错误)。

为什么我不能在构造函数中使用指向成员函数的指针?

3 个答案:

答案 0 :(得分:12)

std::sort需要一个比较器,可以简单地称为compare(a,b)。一个(指向一个)成员函数的指针是不合适的,因为它需要一个对象被调用,所以你需要一个包装器将成员函数绑定到一个对象,并使它只用两个要比较的值来调用它。

在C ++ 11中,您可以将成员函数绑定到对象:

sort(mCurrentGeneration.begin(),mCurrentGeneration.end(),
    std::bind(&GenericGeneticSolver::solutionComparer, this, 
         std::placeholders::_1, std::placeholders::_2));

或者您可以使用lambda:

sort(mCurrentGeneration.begin(),mCurrentGeneration.end(),
    [this](T first,T second) { return solutionComparer(first, second); });

从历史上看,你必须制作自己的仿函数,可能是:

struct SolutionComparer {
    IGenticSolverHelper<T>* helper;

    SolutionComparer(IGenticSolverHelper<T>& helper) : helper(&helper) {}

    bool operator()(T first,T second) {
        return helper->Cost(first) < helper->Cost(second);
    }
};

sort(mCurrentGeneration.begin(),mCurrentGeneration.end(),
    SolutionComparer(mSolverHelper));

答案 1 :(得分:1)

使用c ++ 11,这将起作用:

std::sort( mCurrentGeneration.begin(), mCurrentGeneration.end(), std::bind( &GenericGeneticSolver< T >::solutionComparer, this, std::placeholders::_1, std::placeholders::_2 ) );

答案 2 :(得分:1)

来自@ Mike-Seymour的答案显示了如何让你的程序运作。但似乎您有兴趣了解成员函数无效的原因。

由于术语表明“成员”功能不同于自由功能。成员函数与对象关联。当成员函数正在执行时,有一个“this”指针可用。 “this”指针指的是与成员函数关联的对象的实例。

this指针用于在执行成员函数时访问成员变量。例如,solutionComparer函数引用成员变量mSolverHelper。实际上,访问mSolverHelper对程序员来说很方便,编译器正在执行this->mSolverHelper

this指针作为额外参数提供给成员函数,该参数未向程序员显示或指示。编译器真正将bool solutionComparer (T first,T second)的签名理解为bool solutionComparer (GenericGeneticSolver* this, T first,T second)

因此,当调用成员函数时,还需要对象。例如:MySolver-&gt; solutionComparer(...)。

sort函数的比较器函数签名不了解如何将对象应用于成员函数。比较器功能需要一个自由函数(或它的道德等价物)。您会注意到所提供的所有解决方案都提供了一个对象,以便呼叫solutionComparer

第二个问题出现:为什么调用sort,如果在成员函数中调用sort函数则编译。答案是它没有真正编译并且与模板实例化有关。

模板实例化是懒惰的。编译器只会编译足够的模板类。我认为这与SFINAE有关。您的测试程序可能会实例化该类的实例。例如GenericGeneticSolver求解器。这会导致编译器编译GenericGeneticSolver,但只编译了足够的类来满足链接器。那是构造函数。

如果添加对Evolve()的调用,则编译器也将失败:

GenericGeneticSolver<MyType> solver;
solver.Evolve();

SFINAE的描述应该有助于描述编译器以这种方式工作的方式和原因。

所有这些阴谋都是为了隐藏你,因为你通常不需要知道。但是,在这种情况下,了解语言和编译器的基础以了解如何解决问题是有用的。