How to properly invoke a function object within a class template's member function? Visual Studio Compiler Error C2440 is being generated

帅比萌擦擦* 提交于 2020-06-17 14:23:07

问题


This is a follow up to this question found here!

Now, that I'm able to instantiate the object. I'm now getting a Visual Studio C2440 Compiler Error...


In my original code before it was templated I had a set of member functions that worked on the std::function<double(double)> member object that looked like this:

struct SomeStruct {
    double a_;
    double b_;
    SomeStruct(double a, double b) : a_{a}, b_{b} {}
};

class SomeClass {
private:
    SomeStruct fields_;
    size_t n_;
    std::function<double(double)> func_;

public:
    SomeClass(SomeStruct fields, size_t n, std::function<double(double)> func) :
      fields_{fields}, n_{n}, func_{func}
    {}

    double evaluate() {
        auto distance = fields_.a_ - fields_.b_;  
        auto dx = distance / n_;
        return calculate(dx, fields_);
    }

private:
    double calculate(double dx, const SomeStruct& someStruct) {
        double result = 0;
        for (size_t i = 0; i < n_; ++i) {
            auto dy = func_(someStruct.a_ + i * dx);
            auto area = dy * dx;
            result += area;
        }
        return result;
    }
};

Now my class looks like this:

template<typename Field>
struct SomeStruct {
    Field a_;
    Field b_;
    constexpr SomeStruct(Field a, Field b) : a_{a}, b_{b} {}
};

template<typename FieldType, typename ValueType, typename Func>
class SomeClass {
private:
    SomeStruct<FieldType> fields_;
    size_t n_;
    Func func_; 

public:
    SomeClass(SomeStruct<FieldType> fields, size_t n, Func func) :
        fields_{fields}, n_{n}, func_{func}
    {}

    constexpr ValueType evaluate() {
        auto distance = fields_.a_ - fields_.b_;       
        auto dx = distance / n_;              
        return calculate(dx, fields_);
    }

private:
    constexpr ValueType calculate(ValueType dx, const SomeStruct<FieldType>& someStruct) {
        ValueType result = 0;
        for (size_t i = 0; i < n_; ++i) {
            auto dy = func_(someStruct.a_ + i * dx);
            auto area = dy * dx;
            result += area;
        }
        return result;
    }
};

template<typename FieldType, typename ValueType, typename Func>
SomeClass(SomeStruct<FieldType>, ValueType, Func) ->
SomeClass<FieldType, ValueType, Func>;

I'm now trying to use the class as such:

template<typename T>
constexpr T funcA(T x) {
    return x;
}

template<typename T>
constexpr T funcB(T x) {
    return x*x;
}

int main() {
    SomeClass a{SomeStruct{1.0, 3.0}, 1000, &funcA<double>};
    // a.evaluate();

    SomeClass b{SomeStruct{3.5, 7.5}, 2000, &funcB<double>};
    // b.evaluate();
    return 0;
}

And I'm getting this Visual Studio error...

1>------ Build started: Project: Computations, Configuration: Debug Win32 ------
1>main.cpp
1>c:\users\...\main.cpp(33): error C2440: 'initializing': cannot convert from 'initializer list' to 'Integrator<double,int,T (__cdecl *)(T)>'
1>        with
1>        [
1>            T=double
1>        ]
1>c:\users\...\main.cpp(33): note: No constructor could take the source type, or constructor overload resolution was ambiguous
1>Done building project "Computations.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

This is being generated before I even call its public evaluate() function that will call its private calculate() function...

I'm trying to resolve this compiler error, and I'm trying to make sure that I'm able to invoke the function object, function pointer, functor, lambda that is stored within this class properly...


回答1:


The problem is in the declaration of data member Func:

Func* func_; 

It declares func_ to be of a pointer to the type deduced by a deduction guide:

template <typename FieldType, typename ValueType, typename Func>
SomeClass(SomeStruct<FieldType>, ValueType, Func)
    -> SomeClass<FieldType, ValueType, Func>;

By calling the constructor with an address of a function:

SomeClass a{SomeStruct{1.0, 3.0}, 1000, &funcA<double>};

Func is deduced as:

Func = double(*)(double)

Thus, Func* becomes a pointer to a function pointer:

Func* = double(**)(double)

and that cannot be initialized with &funcA<double>. Instead, use Func alone as the data member type.


I'm trying to make sure that I'm able to invoke the function object, function pointer, functor, lambda that is stored within this class properly

Either use a concept for that or a static assert:

static_assert(std::is_invocable_v<Func&, FieldType&>, "Invalid callable");


来源:https://stackoverflow.com/questions/62164213/how-to-properly-invoke-a-function-object-within-a-class-templates-member-functi

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!