Есть ли способ реализовать ковариантные возвращаемые типы при использовании вектора функций-членов в C ++? - PullRequest
0 голосов
/ 29 января 2019

Мой базовый класс будет выглядеть примерно так (с конструкторами, конечно):

class gBase
{
public:
    // The user will implement a vector of a vector of functions that can be called as g[i][alpha](k)
    virtual vector<cdouble (gBase::*)(double)> operator[] (uint i) = 0;
};

, и я хочу, чтобы возможная реализация выглядела примерно так:

class g : gBase
{
public:
    g() : g_funcs({{g_00, g_01}}) {}
    vector<cdouble (g::*)(double)>  operator[] (uint i)
    {
        return g_funcs[i];
    }
private:
    vector<vector<cdouble (g::*)(double)> > g_funcs;

    // define each function.
    cdouble g_00(double k)
    {
        return 5.0;
    }

    cdouble g_01(double k)
    {
        return 3.0;
    }
};

Где ячто-то не так в определении g_funcs?Я сталкиваюсь с этим:

return type is not identical to nor covariant with return type "std::__1::vector<cdouble (gBase::*)(double), std::__1::allocator<cdouble (gBase::*)(double)>>" of overridden virtual function "gBase::operator[]"

Ответы [ 2 ]

0 голосов
/ 29 января 2019

A std::vector<T> и std::vector<U> не являются ковариантными, даже если T и U являются ковариантными.С типами шаблонов каждая специализация - это собственный уникальный тип, не имеющий отношения к другому, кроме имени шаблона.

Вам нужен вектор общего типа, который можно получить с помощью std::function.Если обе функции возвращают std::vector<std::function<double(double)>>, тогда производная функция переопределит базовую.Затем вы могли бы заполнить функции в векторе, используя лямбду, которая захватывает this, поэтому у него есть объект для вызова функции-члена.

Если вы не можете сделать это, другой вариант будет использоватьstd::vector<std::function<double(gbase const*, double)>> и тогда вам нужно будет передать указатель на объект, для которого вы хотите вызвать функцию, плюс параметр.

0 голосов
/ 29 января 2019

Вам придется вернуть std::vector<cdouble (gBase::*)(double)>, потому что между std::vector<cdouble (gBase::*)(double)> и std::vector<cdouble (g::*)(double)>

нет никакой связи. Обратите внимание, что g[i][alpha](k) не будет работать для вызова одной из этих функций, поскольку вы не передаете g (как gBase), которое будет this.Вместо этого вы можете

(g.*g[i][alpha])(k)

Или с C ++ 17

std::invoke(g[i][alpha], g, k);

Но на самом деле звучит так, будто вы хотите связать this с функциями в векторе.В этом случае вы должны иметь

class gBase
{
public:
    // The user will implement a vector of a vector of functions that can be called as g[i][alpha](k)
    virtual std::vector<std::function<double(double)> > operator[] (uint i) = 0;
};

class g : public gBase
{
public:
    g() : g_funcs({{[this](double k){ return g_00(k); }, [this](double k){ return g_01(k); }}}) {}
    std::vector<std::function<double(double)> > operator[] (uint i)
    {
        return g_funcs[i];
    }
private:
    std::vector<std::vector<std::function<double(double)> > > g_funcs;

    // define each function.
    cdouble g_00(double k)
    {
        return 5.0;
    }

    cdouble g_01(double k)
    {
        return 3.0;
    }
};
...