0

I have a tricky problem and I'm working on it for several hours but can't find a cause and solution of it. Hope someone help me.

I have to demonstrate function being called inside another function( pls see the comment in seminar.cpp)

Below are the files ( I have separated it into header and code files)

main.cpp

#include <iostream>
#include <functional>
#include "seminar.h"

int main()
{
    Tom::Car::Car car;
    Nor::Driving drivingnow;
    std::vector<uint8_t> X = car.road(drivingnow);
    for(int i = 0 ; i < X.size() ; i++){
        std::cout<<unsigned(X[i])<<" ";
    }

    return 0;
}

seminar.h

#pragma once
#include "dist.h"
#include <vector>
#include <bits/stdc++.h>
namespace Tom
{
    namespace Car
    {

        class Car
        {
        public:
            std::vector<uint8_t> road(Nor::Driving &driving);
            
        };
    } // namespace Car
} // namespace Tom

seminar.cpp

#include "seminar.h"
#include <algorithm>
#include <functional>

namespace Tom
{
    namespace Car
    {
        std::vector<uint8_t> drive(Nor::Range &range)
        {
            std::vector<uint8_t> s;
            s.push_back(range.z);
            s.push_back(range.zz);
            return s;
        }

        template <typename T, typename B, typename L>
        std::vector<uint8_t> Content(T Sec, B Byte, L Func)
        {
            Nor::Range Rom;
            std::vector<uint8_t> z = Func(Rom);
            return z;
        }

        std::vector<uint8_t> Car::road(Nor::Driving &driving)
        {
            std::function<std::vector<uint8_t>(Nor::Range &)> Func = &drive;

            return Content(driving, 1, Func);  // passing drive function into content
        }

    } // namespace Car
} // namespace Tom

dist.h

namespace Nor
{

class Driving{
public:
  int x = 1;
};

class Range{
public:
  int z = 50;
  int zz = 100;
};

}

The above code and file structure works correctly and give me the correct expected output ie 50 100 Live here


Now I want to do more separation ie I want the implementation of drive function to move in another file ie in type.cpp

type.cpp

#include <algorithm>
#include "seminar.h"

#include <functional>

namespace Tom
{
    namespace Car

    {
        std::vector<uint8_t> Car::drive(Nor::Range &range)
        {
            std::vector<uint8_t> s;
            s.push_back(range.z);
            return s;
        }

    } // namespace Car
} // namespace Tom

seminar.h

#pragma once
#include "dist.h"
#include <vector>
#include <bits/stdc++.h>
namespace Tom
{
    namespace Car
    {

        class Car
        {
        public:
            std::vector<uint8_t> road(Nor::Driving &driving);
            std::vector<uint8_t> drive(Nor::Range &range);
        };
    } // namespace Car
} // namespace Tom

seminar.cpp

#include "seminar.h"
#include <algorithm>

#include <functional>

namespace Tom
{
    namespace Car
    {
        

        template <typename T, typename B, typename L>
        std::vector<uint8_t> Content(T Sec, B Byte, L Func)
        {
            Nor::Range Rom;
            std::vector<uint8_t> z = Func(Rom);
            return z;
        }

        std::vector<uint8_t> Car::road(Nor::Driving &driving)
        {
            std::function<std::vector<uint8_t>(Nor::Range &)> Func = &drive;

            return Content(driving, 1, Func);
        }

    } // namespace Car
} // namespace Tom

Live here After doing this I am getting an below error:

seminar.cpp: In member function ‘std::vector<unsigned char> Tom::Car::Car::road(Nor::Driving&)’:
seminar.cpp:22:71: error: ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function.  Say ‘&Tom::Car::Car::drive’ [-fpermissive]
   22 |             std::function<std::vector<uint8_t>(Nor::Range &)> Func = &drive;
      |                                                                       ^~~~~
seminar.cpp:22:71: error: conversion from ‘std::vector (Tom::Car::Car::*)(Nor::Range&)’ to non-scalar type ‘std::function(Nor::Range&)>’ requested

Taking reference from this answer

I tried this way :

std::function<std::vector<uint8_t>(Nor::Range)> f = std::bind(&Car::drive, this);

And Got this error:

/usr/include/c++/9/functional:775:7: error: static assertion failed: Wrong number of arguments for pointer-to-member
  774 |       static_assert(_Varargs::value
      |                               ~~~~~
  775 |       ? sizeof...(_BoundArgs) >= _Arity::value + 1
      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  776 |       : sizeof...(_BoundArgs) == _Arity::value + 1,
      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
seminar.cpp: In member function ‘std::vector<unsigned char> Tom::Car::Car::road(Nor::Driving&)’:
seminar.cpp:23:73: error: conversion from ‘std::_Bind_helper (Tom::Car::Car::*)(Nor::Range&), Tom::Car::Car*>::type’ {aka ‘std::_Bind (Tom::Car::Car::*(Tom::Car::Car*))(Nor::Range&)>’} to non-scalar type ‘std::function(Nor::Range)>’ requested
   23 |            std::function<std::vector<uint8_t>(Nor::Range)> f = std::bind(&Car::drive, this);
      |                                                                ~~~~~~~~~^~~~~~~~~~~~~~~~~~~
seminar.cpp:25:40: error: ‘Func’ was not declared in this scope
   25 |             return Content(driving, 1, Func);

See here live


I don't know correctly what I am doing wrong in moving the implementation of drive function can someone please help with implementing the corrrect way.

Note:: I'm fine if the solution uses another way to pass the function ie by not using std::function . Thanks

2 Answers2

2

In seminar.cpp, here:

std::function<std::vector<uint8_t>(Nor::Range &)> Func = &drive;

drive is a member function. It needs the this pointer to be called.

You can easily solve this by wrapping it in a lambda:

std::function<std::vector<uint8_t>(Nor::Range &)> Func = [this](Nor::Range & r) {
    return this->drive(r);
};

If you prefer the std::bind method that you tried, you need a placeholder for the Nor::Range& parameter:

std::function<std::vector<uint8_t>(Nor::Range &)> Func = std::bind(&Car::drive, this, std::placeholders::_1);

Also, you really don't need the std::function at all since it's a local variable that you immediately pass to another function, so just use auto instead (or pass it directly without an intermediate variable):

auto Func = [this](Nor::Range & r) {
    return this->drive(r);
};
Nelfeal
  • 12,593
  • 1
  • 20
  • 39
  • 1
    You could also just pass the lambda directly (since the OP isn't required to use `std::function`). – john Nov 19 '22 at 14:15
  • Making the member function `static` is another possibility. – Jarod42 Nov 19 '22 at 14:28
  • @Jarod42 Sure but that's a change in design, and it's far from the only change I would make in OP's code. Presumably it's not the actual code but an awkwardly simplified version. – Nelfeal Nov 19 '22 at 14:35
1

Non-static member function pointers should be initialized in this way:

return_type (class_name::*pointer_name)(argument_types ...) = &class_name::function_name;

They should be called in this way:

(instance_name.*pointer_name)(arguments ...);

Such pointers can be assigned to std::function objects, which is a bit complicated. You should pay attention that this is an implicit argument in a member function, so the pointer type of the class should be explicitly declared as an argument in the template of the std::function object in such an assignment. For example,

std::function<std::vector<uint8_t>(Car *, Nor::Range &)> Func = &Car::drive;

You also mentioned the std::bind function. In this case, you should use std::placeholders to hold the place for undetermined arguments. Pay attention that the template of the std::function object should only contain undetermined arguments.

std::function<std::vector<uint8_t>(Nor::Range &)> Func = std::bind(&Car::drive, this, std::placeholders::_1);

You may try auto:

auto Func = std::bind(&Car::drive, this, std::placeholders::_1);

The std::placeholders::_1 allows the argument Nor::Range &range to be passed to the function Car::drive later. The implicit argument this should also be explicitly used in the std::bind function.

  • Sorry, there is one mistake. The `bind` function can be assigned to `function` objects, although it doesn't return a `function` object. But I think it is much more convenient to use `auto`. – Shuangcheng Ni Nov 19 '22 at 15:03
  • "they cannot be assigned to `function` objects" - [false](https://godbolt.org/z/E97q1xrv8). – Nelfeal Nov 19 '22 at 16:14
  • Thanks a lot for pointing out my mistake. I forgot to include the pointer of an object as a parameter here. – Shuangcheng Ni Nov 19 '22 at 16:51