Использовать переменную функцию в качестве аргумента шаблона - PullRequest
0 голосов
/ 20 октября 2018

Я бы хотел, чтобы следующий код работал без изменения классов Child1 и Child2:

#include <iostream>

int triple(int a) {
    return a * 3;
}

int add(int a, int b) {
    return a + b;
}

template<int (*F)(int)>
class Parent {
    public:
        Parent(int a) {
            std::cout << "constructed: " << F(a) << std::endl;
        }
};

class Child1 : Parent<triple> {
    public:
        Child1(int a) : Parent(a) {}
};

/*class Child2 : Parent<add> {
    public:
        Child2(int a, int b) : Parent(a, b) {}
};*/

int main() {
    Child1 child(4);
    //Child2 child(5, 6);
    return 0;
}

Как вы можете видеть, например, Child1 наследуется от Parent, который был создан с помощью функции triple.Таким образом, когда экземпляр Child1 создается с четырьмя, он выдает "constructed: 12".

В отличие от этого, Child2 закомментирован, поскольку он, очевидно, еще не работает.В основной функции я пытаюсь передать два аргумента конструктору Child2, так же как и базовая функция add() ожидает этого.Тем не менее, конструктор Parent принимает только один аргумент и, возможно, для решения потребуется template<typename Args...> перед ним.Кроме того, классу Parent потребуется аргумент шаблона, такой как int (*F)(Args...).В конце концов, создание экземпляра Child2, как это делает основная функция, должно вывести «constructed: 11».

Как я могу это сделать, то есть создать шаблонный аргумент, который является функцией, которая может иметь любое количество параметров?Опять же, обратите внимание, что код класса Parent - единственное, что может быть изменено.

Ответы [ 2 ]

0 голосов
/ 20 октября 2018

Слишком поздно играть?

Я предлагаю вариант ответа VTT C ++ 17 на основе auto, который использует специализацию класса для извлечения типов ввода Args... (и типа Ret)., если полезно).

Я имею в виду

template <auto>
class Parent;

template <typename Ret, typename ... Args, Ret(*F)(Args...)>
class Parent<F>
 {
   public:
      Parent (Args const & ... as)
       { std::cout << "constructed: " << F(as...) << std::endl; }
 };

Ниже приведен полный пример компиляции

#include <iostream>

int triple (int a)
 { return a * 3; }

long add (int a, int b)
 { return a + b; }

template <auto>
class Parent;

template <typename Ret, typename ... Args, Ret(*F)(Args...)>
class Parent<F>
 {
   public:
      Parent (Args const & ... as)
       { std::cout << "constructed: " << F(as...) << std::endl; }
 };

class Child1 : public Parent<triple>
 {
    public:
        Child1 (int a) : Parent{a}
         { }
 };

class Child2 : public Parent<add>
 {
    public:
        Child2 (int a, int b) : Parent{a, b}
         { }
 };

int main()
 {
   Child1 c1{4};
   Child2 c2{5, 6};
 }

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

0 голосов
/ 20 октября 2018

С C ++ 17 Вы можете использовать выведенный не типовой параметр шаблона и сделать конструктор вариационным шаблоном:

template<auto x_pointer_to_function>
class Parent
{
    public:
    template<typename... x_Args>
    Parent(x_Args &&... args)
    {
        std::cout << "constructed: " << ((*x_pointer_to_function)(::std::forward<x_Args>(args)...)) << std::endl;
    }
};

онлайн-компилятор

...