Как использовать функцию-член шаблона базового класса в производном?

как использовать функцию шаблона базового класса в производном случае?

Пример:

Class A{

    protected:
       template<typename... Args>
            std::vector<torch::Tensor> generate_value(const size_t& generated_points, std::function<int(const Args&...)> function, const Args&... args);
};
class B : protected A{
   public:
      B() : A(){}
   protected:
     std::vector<torch::Tensor> generate_values(const size_t& generated_points, const size_t& column){
        return this->generate_values(generated_points, std::bind(&A::inner_generation, this, std::placeholders::_1), column);
     }

     <torch::Tensor inner_generation(const size_t& column);
};

При компиляции с использованием Clang я получаю следующую ошибку:

 error: no matching member function for call to 'generate_values'
        return this->generate_values(generated_points, function, column);
               ~~~~~~^~~~~~~~~~~~~~~
note: candidate template ignored: could not match 'std::function<torch::Tensor (const Args &...)>
            std::vector<torch::Tensor> generate_values(const size_t& generated_points, std::function<torch::Tensor(const Args&...)> function, const Args&... args)

Я не уверен, в чем проблема.

Я надеюсь, что кто-то может направить меня.

Изначально у меня была функция с таким же названием, она находила только ту, что в class B. Я потом поменял имена, он до сих пор не найден. Я не уверен, что это из-за template.

<torch::Tensor ? что это?
463035818_is_not_a_number 22.05.2023 10:03

пожалуйста, опубликуйте минимальный воспроизводимый пример

463035818_is_not_a_number 22.05.2023 10:04

Это проблема дизайна: не смешивайте статический и динамический полиморфизм. Выберите любой из них, поскольку вы не можете создать виртуальный шаблон в базовом классе. Таким образом, либо ваш базовый класс имеет полную реализацию шаблона, которую можно использовать в производном классе, либо вам нужен виртуальный метод (который не является шаблонным)

Pepijn Kramer 22.05.2023 10:08

@PepjinKramer в коде нет виртуального метода/динамического полиморфизма.

463035818_is_not_a_number 22.05.2023 10:20

@463035818_is_not_a_number torch::Tensor тип из ссылки

mas 22.05.2023 10:28
<torch::Tensor inner_generation(const size_t& column); — синтаксическая ошибка. А минимальный воспроизводимый пример не требует std::vector, std::function или torch::Tensor. Если вы используете вещи, вы не должны удалять включения из кода. Код, который вы разместили, вызовет много ошибок компилятора.
463035818_is_not_a_number 22.05.2023 10:31
Class A тоже не правильно
463035818_is_not_a_number 22.05.2023 10:32

кроме того, метод называется A::generate_value, метод, который вы пытаетесь вызвать, называется generate_values. В этом коде слишком много опечаток.

463035818_is_not_a_number 22.05.2023 10:34

@ 463035818_is_not_a_number извините за путаницу. Я новичок на платформе, и мне нужно руководство. Спасибо, что поделились ссылкой, так что с этого аспекта можно улучшить.

mas 22.05.2023 10:35
std::function — довольно дорогой зверь — если у вас все равно есть шаблон, почему бы вам просто не принять его как еще один параметр шаблона? template <typename F, typename ... A> std::vector<...> gen(/*...*/ F&& f, A&& ... a) { /*...*/ f(std::forward<A>(a)...; /*...*/ } — тогда вы могли бы легко передать лямбды, хотя std::bind все равно было бы хорошо.
Aconcagua 22.05.2023 10:37

честно говоря, это не относится к SO, что опубликованный вами код не воспроизводит ошибку. Если вам нужна помощь с некоторым кодом, вам нужно показать этот код, а не другой код, в котором есть другие ошибки.

463035818_is_not_a_number 22.05.2023 10:38

вы можете отредактировать вопрос, чтобы показать свой фактический код

463035818_is_not_a_number 22.05.2023 10:44
Демонстрация моего предложения…
Aconcagua 22.05.2023 11:07

На самом деле, с общим параметром шаблона вы можете сделать это еще проще, просто примите функтор и позвольте лямбде заботиться о дополнительных параметрах: template <typename F> int A::demo(int n, F&& f) { return n + f(); } int B::demo(int n, int x, int y, int z) { return A::demo(n, [this, x, y, z]() { return myDemo(x, y, z); }); или немного проще с захватом по умолчанию [=]() { /*...*/ }

Aconcagua 22.05.2023 11:11

(Лямбда и) возвращаемый тип std::bind не является std::function, поэтому не соответствует вашему шаблону.

Jarod42 22.05.2023 11:53

@ Jarod42 Jarod42 Я тоже об этом, я пробовал лямбда-функцию, но получаю ту же ошибку.

mas 22.05.2023 23:46

@Aconcagua Спасибо за этот комментарий. Я действительно не знал, должен ли я использовать std::function или просто шаблон. Я дам ему попробовать. Это очень уместно.

mas 22.05.2023 23:47

@Aconcagua Ваше решение именно то, что мне нужно. Рассмотрю возможность добавления в качестве ответа, чтобы я мог проголосовать за него. Я уверен, что это может помочь другим людям, которые могут подумать о том, чтобы сделать что-то подобное. Спасибо

mas 23.05.2023 05:28
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
18
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

std::function довольно дорог в использовании и мало гибок — если вы согласитесь с еще одним параметром шаблона, вы станете более эффективным, более гибким и даже получите более простой код:

class A
{
protected:
    template<typename F, typename... Args>
    std::vector<torch::Tensor> generate_value
    (
        size_t generated_points, // no benefit from reference...
        F&& f // the function/functor to execute
        Args&&... args // allows perfect forwarding
    )
    {
        f(std::forward<Args>(args)...);
    } 
};

std::vector<torch::Tensor> B::generate_values(size_t generated_points, size_t column)
{
    return generate_values
    (
        generated_points,
        // simply use a lambda, it's just more convenient:
        [this](size_t column) { return inner_generation(column); },
        // though the result of `bind` would be just as valid...
        column // and the parameter...
    );
}

Хотя при использовании лямбда-выражений (или std::bind, если вы привязываете значения напрямую вместо использования заполнителей), вам даже не нужны дополнительные параметры:

template<typename F>
std::vector<torch::Tensor> A::generate_value(size_t generated_points, F&& f)
{
    f();
}

std::vector<torch::Tensor> B::generate_values(size_t generated_points, size_t column)
{
    return generate_values
    (
        generated_points,
        [this, column] { return inner_generation(column); }
        // alternatively with default bindings:
        //[=] { return inner_generation(column); }
    );
}

Какой выбрать? Что ж, в основном дело личного вкуса — если вы не хотите делать одно и то же несколько раз с разными переменными, то первый вариант предпочтительнее, поскольку вам не нужно создавать несколько лямбда-выражений:

std::vector<torch::Tensor> B::generate_values
(
    size_t generated_points,
    size_t column1,
    size_t column2 // now one more...
)
{
    auto gen = [this](size_t column) { return inner_generation(column); };
    auto v1 = generate_values(generated_points, gen, column1);
    auto v2 = generate_values(generated_points, gen, column2);
    // union both, create difference or do whatever is appropriate...
    return ...;
}

Этот последний пример может не иметь смысла в вашем конкретном случае, но может сыграть роль в других сценариях;)

Боковое примечание: просто для объяснения: исходный вариант не работает ни из-за результата bind, ни из-за того, что лямбда на самом деле является объектом std::function, поэтому не соответствует параметру вашего шаблона. Вы можете решить, создав объект std::function явно:

return A::generate_values
(
    generated_points,
    std::function([this](size_t const& column) { return inner_generation(column); }),
    // alternatively with `bind`ing, though the place holder makes
    // explicitly specifying the template argument necessary:
    //std::function<torch::Tensor(size_t const&)>
    //(
    //    std::bind(&B::inner_generation, this, std::placeholders::_1)
    //),
    column
);

Также обратите внимание, что в исходном коде вопроса возвращаемые типы экземпляров std::function также не совпадают (сначала int, затем torch::Tensor — если только torch::Tensor не является typedef для int…).

Другие вопросы по теме