У меня есть сложная проблема, и я работаю над ней несколько часов, но не могу найти причину и решение. Надеюсь, кто-нибудь поможет мне.
Мне нужно продемонстрировать, что функция вызывается внутри другой функции (пожалуйста, смотрите комментарий в семинаре.cpp)
Ниже приведены файлы (я разделил их на заголовочные файлы и файлы кода)
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;
}
семинар.ч
#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
семинар.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
расст.ч
namespace Nor
{
class Driving{
public:
int x = 1;
};
class Range{
public:
int z = 50;
int zz = 100;
};
}
Приведенный выше код и файловая структура работают правильно и дают мне правильный ожидаемый результат, т.е. 50 100
Жить здесь
Теперь я хочу сделать больше разделения, то есть я хочу, чтобы реализация функции drive
переместилась в другой файл, то есть в type.cpp
тип.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
семинар.ч
#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
семинар.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
Жить здесь После этого я получаю следующую ошибку:
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
Со ссылкой на этот ответ
Я пробовал так:
std::function<std::vector<uint8_t>(Nor::Range)> f = std::bind(&Car::drive, this);
И получил эту ошибку:
/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);
Смотрите здесь в прямом эфире
Я не знаю правильно, что я делаю неправильно при перемещении реализации функции drive
, может кто-нибудь помочь с правильной реализацией.
Примечание: я не против, если в решении используется другой способ передачи функции, т. е. без использования std::function
. Спасибо
Как показано, методы участника могут быть static
(один из способов решения вашей проблемы).
В семинаре.cpp, здесь:
std::function<std::vector<uint8_t>(Nor::Range &)> Func = &drive;
drive
— это функция-член. Для вызова требуется указатель this
.
Вы можете легко решить это, обернув его в лямбду:
std::function<std::vector<uint8_t>(Nor::Range &)> Func = [this](Nor::Range & r) {
return this->drive(r);
};
Если вы предпочитаете метод std::bind
, который вы пробовали, вам нужен заполнитель для параметра Nor::Range&
:
std::function<std::vector<uint8_t>(Nor::Range &)> Func = std::bind(&Car::drive, this, std::placeholders::_1);
Кроме того, вам вообще не нужна std::function
, так как это локальная переменная, которую вы сразу же передаете другой функции, поэтому просто используйте вместо нее auto
(или передайте ее напрямую без промежуточной переменной):
auto Func = [this](Nor::Range & r) {
return this->drive(r);
};
Вы также можете просто передать лямбду напрямую (поскольку OP не требуется для использования std::function
).
Создание функции-члена static
— еще одна возможность.
@ Jarod42 Конечно, но это изменение дизайна, и это далеко не единственное изменение, которое я бы внес в код OP. Предположительно, это не настоящий код, а неловко упрощенная версия.
Указатели нестатических функций-членов должны быть инициализированы следующим образом:
return_type (class_name::*pointer_name)(argument_types ...) = &class_name::function_name;
Их следует называть так:
(instance_name.*pointer_name)(arguments ...);
Такие указатели можно назначать объектам std::function
, что немного сложно. Следует обратить внимание, что this
является неявным аргументом в функции-члене, поэтому тип указателя класса должен быть явно объявлен как аргумент в шаблоне объекта std::function
в таком присваивании. Например,
std::function<std::vector<uint8_t>(Car *, Nor::Range &)> Func = &Car::drive;
Вы также упомянули функцию std::bind
. В этом случае вы должны использовать std::placeholders
, чтобы оставить место для неопределенных аргументов. Обратите внимание, что шаблон объекта std::function
должен содержать только неопределенные аргументы.
std::function<std::vector<uint8_t>(Nor::Range &)> Func = std::bind(&Car::drive, this, std::placeholders::_1);
Вы можете попробовать auto
:
auto Func = std::bind(&Car::drive, this, std::placeholders::_1);
std::placeholders::_1
позволяет передать аргумент Nor::Range &range
функции Car::drive
позже. Неявный аргумент this
также должен явно использоваться в функции std::bind
.
Извините, есть одна ошибка. Функция bind
может быть назначена объектам function
, хотя она не возвращает объект function
. Но я думаю, что гораздо удобнее использовать auto
.
"они не могут быть назначены function
объектам" - false.
Большое спасибо, что указали на мою ошибку. Я забыл включить указатель объекта в качестве параметра здесь.
У вас уже есть пространство имен
Car
, вы действительно хотитеclass Car
с методом (который должен быть статическим)?