Как вывести второй тип параметра из первого параметра? - PullRequest
0 голосов
/ 08 сентября 2018

Я новичок в шаблон-метапрограммировании. Второй параметр будет таким же, как переданный параметр функции. Я хочу вывести второй тип параметра из Func.

template<typename Func>
void execute(Func func, decltype(Func) t) 
{
    std::cout << func(t) << std::endl;
}

int main() 
{
    std::function<int(float)> func1 = [](float f) { return int(f); };
    execute(func1,1.5);
    return 0;
}

Это работает, но я не хочу объявлять дополнительные typenameme T, поскольку информация уже доступна в Func, так почему бы не сделать вывод.

template<typename Func, typename T>
void execute(Func func, T t) 
{
    std::cout << func(t) << std::endl;
}

Ответы [ 5 ]

0 голосов
/ 08 сентября 2018

Вы должны , а не сделать это. Если вы это сделаете, ваш пример перестанет работать , потому что ваша функция int(float), а аргумент double.

#include <functional>
#include <iostream>

template<typename Arg>
void execute(std::function<int(Arg)> func, Arg t) {
    std::cout << func(t) << std::endl;
}

int main() {
    std::function<int(float)> func1 = [](float f) { return int(f); };
    execute(func1,1.5);
    return 0;
}

Это не скомпилируется. Живая демоверсия .

Оставайтесь с параметром T, все в порядке.

0 голосов
/ 08 сентября 2018

Я хочу вывести второй тип параметра из Func

Я не хочу объявлять дополнительные typename T

Я не вижу ничего простогорешение вашего требования, кроме передачи вызываемого объекта в функцию, после связывания с аргументом .

Следующее обеспечит выполнение вашего второго требования и не потребует значительного изменения исходного кода.

#include <functional>
#include <iostream>

template<typename Func>
void execute(Func func) {
    std::cout << func() << std::endl;
}
int main() 
{
    auto func1 = std::bind([](float f) { return int(f); }, 2.5f);
    execute(func1);
    return 0;
}
0 голосов
/ 08 сентября 2018

Вот пример:

#include <tuple>
#include <type_traits>

template <typename> struct function_traits;

template <typename Function>
struct function_traits
    : public function_traits<decltype(
          &std::remove_reference<Function>::type::operator())> {};

template <typename ClassType, typename ReturnType, typename... Arguments>
struct function_traits<ReturnType (ClassType::*)(Arguments...) const>
    : function_traits<ReturnType (*)(Arguments...)> {};

/* support the non-const operator ()
 * this will work with user defined functors */
template <typename ClassType, typename ReturnType, typename... Arguments>
struct function_traits<ReturnType (ClassType::*)(Arguments...)>
    : function_traits<ReturnType (*)(Arguments...)> {};

template <typename ReturnType, typename... Arguments>
struct function_traits<ReturnType (*)(Arguments...)> {
  typedef ReturnType result_type;

  using argument_tuple = std::tuple<Arguments...>;
  template <std::size_t Index>
  using argument = typename std::tuple_element<Index, argument_tuple>::type;

  static const std::size_t arity = sizeof...(Arguments);
};

template <typename Function, std::size_t Index>
using nth_argument_type =
    typename function_traits<Function>::template argument<Index>;

#include <iostream>
using namespace std;

template <typename FN>
void execute(FN func, nth_argument_type<FN,0> arg0) {
  std::cout << func(arg0) << std::endl;
};

int main() {
  int i = 7;
  auto fn = [](int a) { return a * a; };
  auto fn2 = [](int a) mutable { return a * a; };
  execute(fn, 5);
  execute(fn, i);
  execute(fn2, 5);
  execute(fn2, i);
};
0 голосов
/ 08 сентября 2018

В вашем примере нет необходимости знать точные типы аргументов, поэтому самое простое решение здесь - использовать шаблон с переменным числом аргументов. Просто возьмите пакет параметров и отправьте их:

template<typename Func, typename... Args>
void execute(Func func, Args&&... a) {
    std::cout << func(std::forward<Args>(a)...) << std::endl;
}

int main() {
    auto func1 = [](float f) { return int { f }; };
    execute(func1, 1.5);
    auto func2 = [](int i) { return float { i }; };
    execute(func2, 15);
    auto func3 = [](int a, int b, int c) { return a * b + c; };
    execute(func3, 3, 4, 5);
    return 0;
}
0 голосов
/ 08 сентября 2018

Что вам нужно, так это черта типа, которая обеспечивает доступ к типам, используемым в сигнатуре функции. В стандартной библиотеке нет такой черты типа. Таким образом, вам нужно либо использовать библиотеку, которая ее реализует, либо реализовать ее самостоятельно.

Если вы можете использовать boost, они точно реализовали это в своих чертах типа: https://www.boost.org/doc/libs/1_68_0/libs/type_traits/doc/html/boost_typetraits/reference/function_traits.html Вы могли бы использовать член argN_type, чтобы получить тип аргумента N-го типа.

Если вы не можете использовать boost, вам нужно будет реализовать собственную черту типа, чтобы сделать типы аргументов доступными. Это может выглядеть так:

// Base case for non-function types
template<typename T>
struct func_types { };

// Case for any generic function signature
template<typename Return, typename ...Args>
struct func_types<Return(Args...)>
{
    using ReturnType = Return;
    using ArgsTuple = std::tuple<Args...>;

    template<std::size_t N>
    struct args
    {
        using Type = std::tuple_element_t<N, ArgsTuple>;
    };
};

// Specialization for function pointers
template<typename Return, typename ...Args>
struct func_types<std::function<Return(Args...)>> : public func_types<Return(Args...)> { };

// Specialization for std::function
template<typename Return, typename ...Args>
struct func_types<std::function<Return(Args...)>> : public func_types<Return(Args...)> { };


// All further specializations for member functions,
// lambdas, etc. are left as an exercise to the reader

template<typename Func>
void execute(Func func, typename func_types<Func>::template args<0>::Type t)
{
    std::cout << func(t) << std::endl;
}

Этот пример является в основном урезанной версией этого сообщения в блоге . При этом используются функции, добавленные в C ++ 14, поэтому вам нужно будет скомпилировать эту версию или более новую.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...