我如何传递变量到一个函数,与任何签名,使用模板

How do I pass variables into a function, with any signature, using templates?

本文关键字:任何签 函数 一个 变量 何传递      更新时间:2023-10-16

我的问题如下。我想在包装器中调用任何自由函数,并且我想在包装器中自动传递参数。

的想法是通过函数调用传递参数,如GetArgument<float>()。最后,我想从虚拟机获取这些值,并将它们传递给我要绑定的函数。我需要将具有正确类型的正确GetArgument<T>放置在函数调用中的正确位置。

这是我尝试的一个最小的工作示例。主要:

#include "FunctionWrapper.h"
#include <iostream>
void say( int val ) {
    std::cout << "called with " << val << std::endl;
}
int main() {
    InvokeWithArguments( say );
    return 0;
}

这就是奇迹发生的地方。在源代码的末尾,我得到一个编译器错误:

#pragma once
#include <cstdlib>
#include <cstdint>
#include <tuple>
#include <type_traits>
/*
 * FUNCTION TRAITS
 */
template< typename F >
struct FunctionTraits;
template< typename R, typename... Args >
struct FunctionTraits< R( Args... ) > {
    using ReturnType = R;
    constexpr static const uint32_t arity = sizeof...( Args );
    template< std::size_t N >
    struct Argument {
        static_assert( N < arity, "FunctionTraits error: invalid argument count parameter" );
        using type = typename std::tuple_element< N, std::tuple< Args... > >::type;
    };
};
/*
 * ARGUMENT GETTER (for demonstration)
 **/
template< typename T >
T GetArgument() {}
template<>
float GetArgument() {
    return 3.3f;
}
template<>
int GetArgument() {
    return 5;
}
/*
 * AUTOMATIC INVOCATION
 **/
template< typename Function, std::size_t... index >
decltype( auto ) InvokeHelper( Function&& f, std::index_sequence<index...> ) {
    using Traits = FunctionTraits< decltype(f) >;
    // COMPILER FAILS HERE, EXPECTS ) BEFORE :: TOKEN
    return f( GetArgument< Traits::Argument<index>::type >()... );
}
template< typename Function >
decltype( auto ) InvokeWithArguments( Function&& f ) {
    constexpr auto Arity = FunctionTraits< decltype(f) >::arity;
    return InvokeHelper( std::forward<Function>( f ), std::make_index_sequence<Arity>{} );
}

我不明白为什么return f( GetArgument< Traits::Argument<index>::type >()... );失败了。据我所知,Traits::Argument<index>::type是一种类型,所以我不知道为什么编译器会期望在它中间关闭函数调用。

最后,一个小的完整性检查,因为我是这样一个模板编程新手。我希望在函数调用的括号之间有一个逗号分隔的GetArgument<T>调用列表。我的代码就是这么做的吗?

你应该使用:

return f( GetArgument< typename Traits::template Argument<index>::type >()... );
//                     ^^^^^^^^         ^^^^^^^^^

在此之后,编译器会抱怨你的FunctionTraits<void(&)(int)>不能被实例化,这可以通过通过std::remove_reference删除函数类型中的引用来修复。

这是由于void(int)不同于void(&)(int), void(*)(int)不同造成的。前者是函数类型,后者是函数引用类型,后者是函数指针类型。

所有这些将产生:

template< typename Function, std::size_t... index >
decltype( auto ) InvokeHelper( Function&& f, std::index_sequence<index...> ) {
    using Traits = FunctionTraits< typename std::remove_reference<decltype(f)>::type >;
    //                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^           ^^^^^^^
    return f( GetArgument< typename Traits::template Argument<index>::type >()... );
    //                     ^^^^^^^^         ^^^^^^^^^
}
template< typename Function >
decltype( auto ) InvokeWithArguments( Function&& f ) {
    constexpr auto Arity = FunctionTraits< typename std::remove_reference<decltype(f)>::type >::arity;
    //                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^           ^^^^^^^
    return InvokeHelper( std::forward<Function>( f ), std::make_index_sequence<Arity>{} );
}

现场演示