简体   繁体   English

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

[英]How to pass to sort predicate that is a member function, from the constructor

I have the following code : 我有以下代码:

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

In the constructor I'm filling a vector with members, and then I'm trying to sort this vector by passing a predicate to the Sort function, the predicate is a member function called `solutionComparer. constructor我正在使用成员填充向量,然后我尝试通过将谓词传递给Sort函数来对此向量进行Sort ,谓词是一个名为`solutionComparer的成员函数。

Unfortunately it does not compile, the compiler is not happy with using pointer to member functions in the constructor, i tried the same line in the "Evolve" function, and it does compile. 不幸的是它没有编译,编译器不满意在构造函数中使用指向成员函数的指针,我在“Evolve”函数中尝试了相同的行,并且它确实编译。

The error i get is : 我得到的错误是:

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

I tried to do what the error suggested but it didn't compile either (some random error in the sort function). 我试图做错误建议但它也没有编译(sort函数中的一些随机错误)。

Why can't i use pointer to a member function in the constructor ? 为什么我不能在构造函数中使用指向成员函数的指针?

std::sort requires a comparator which can simply be called as compare(a,b) . std::sort需要一个比较器,可以简单地称为compare(a,b) A (pointer to a) member function isn't suitable, since it requires an object to be called on, so you'll need a wrapper to bind the member function to an object and make it callable with just the two values to compare. 一个(指向一个)成员函数的指针是不合适的,因为它需要一个对象被调用,所以你需要一个包装器将成员函数绑定到一个对象,并使它只用两个要比较的值来调用它。

In C++11, you can bind a member function to an object: 在C ++ 11中,您可以将成员函数绑定到对象:

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

or you can use a lambda: 或者你可以使用lambda:

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

Historically, you would have to make your own functor, perhaps along the lines of: 从历史上看,你必须制作自己的仿函数,可能是这样的:

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

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

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

The answer from @Mike-Seymour shows how to make your program work. @ Mike-Seymour的答案显示了如何使你的程序工作。 But it seems you are interested to understand why a member function does not work. 但似乎您有兴趣了解为什么成员函数不起作用。

As the terminology indicates a "member" function is different from a free function. 由于术语表示“成员”功能不同于自由功能。 Member functions are associated with an object. 成员函数与对象关联。 While a member function is executing there is a "this" pointer available. 当成员函数正在执行时,有一个“this”指针可用。 The "this" pointer refers to the instance of the object associated with the member function. “this”指针指的是与成员函数关联的对象的实例。

The this pointer is used to access the member variables while executing the member function. this指针用于在执行成员函数时访问成员变量。 For example, the solutionComparer function refers to the member variable mSolverHelper . 例如, solutionComparer函数引用成员变量mSolverHelper Accessing mSolverHelper is a convenience to the programmer in reality, the compiler is executing this->mSolverHelper . 实际上,访问mSolverHelper对程序员来说很方便,编译器正在执行this->mSolverHelper

The this pointer is provided to the member function as an extra parameter that is not shown or indicated to the programmer. this指针作为额外参数提供给成员函数,该参数未向程序员显示或指示。 The signature for bool solutionComparer (T first,T second) is really understood by the compiler to be bool solutionComparer (GenericGeneticSolver* this, T first,T second) . bool solutionComparer (T first,T second)的签名实际上被编译器理解为bool solutionComparer (GenericGeneticSolver* this, T first,T second)

Therefore when a member function is called an object is also required. 因此,当调用成员函数时,还需要对象。 For example: MySolver->solutionComparer(…). 例如:MySolver-> solutionComparer(...)。

The comparator function signature to the sort function does not understand how to apply an object to the member function. sort函数的比较器函数签名不了解如何将对象应用于成员函数。 The comparator function requires a free function (or it's moral equivalent). 比较器功能需要一个自由函数(或它的道德等价物)。 You'll notice that all of the solutions offered provide an object in order to call solutionComparer . 您会注意到所提供的所有解决方案都提供了一个对象,以便调用solutionComparer

A second question occurs: why does the call to sort, compile if the sort function is called in a member function. 第二个问题出现:为什么调用sort,如果在成员函数中调用sort函数则编译。 The answer is it doesn't really compile and is related to template instantiation. 答案是它没有真正编译并且与模板实例化有关。

Template instantiate is lazy. 模板实例化是懒惰的。 The compiler will only compile the enough of a template class that is required. 编译器只会编译足够的模板类。 I believe this has to do with SFINAE . 我相信这与SFINAE有关 Your test program likely instantiates an instance of the class. 您的测试程序可能会实例化该类的实例。 eg GenericGeneticSolver solver. 例如GenericGeneticSolver求解器。 This causes the compiler to compile GenericGeneticSolver but only enough of the class is compiled to satisfy the linker. 这会导致编译器编译GenericGeneticSolver,但只编译了足够的类来满足链接器。 That is the constructor. 那是构造函数。

If you add a call to Evolve() then the compiler will also fail: 如果添加对Evolve()的调用,则编译器也将失败:

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

The description of SFINAE should help to describe how and why the compiler works in this fashion. SFINAE的描述应该有助于描述编译器以这种方式工作的方式和原因。

All of these machinations are meant to be hidden from you, as you typically don't need to know. 所有这些阴谋都是隐藏的,因为您通常不需要知道。 However, in cases like this it is useful to understand the underpinnings of the language and compiler in order to understand how to solve the problem. 但是,在这种情况下,理解语言和编译器的基础以了解如何解决问题是有用的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM