用函数名作为字符串将 std::function 包装在类中

Posted

技术标签:

【中文标题】用函数名作为字符串将 std::function 包装在类中【英文标题】:Wrap std::function in class with function name as string 【发布时间】:2019-07-21 12:10:17 【问题描述】:

我正在尝试将std::function 包装在一个类中,并将函数名称的可读string 添加到std::function

我确实想出了这个简单的课程 (在 header.hpp 中定义)

template <typename... Args>
class CExtended_Function

public:
    explicit CExtended_Function(
        const std::function<void(Args...)>& func_type, const std::string& func_name)
        : func(func_type)
        , function_name(func_name)
    
    

    /// Function
    const std::function<void(Args...)> func;

    /// Function Name
    const std::string function_name;
;

我自己的 make 函数看起来像这样。想法是将函数名称作为模板参数传递给 make 函数。 make 函数应该创建一个std::function 实例和一个std::string 实例。

(在 header.hpp 中定义)

template <typename Func_T, typename... Args>
CExtended_Function<Args...> Make_Extended_Function()

    std::function<void(Args...)> func(Func_T);
    std::string func_name(NCommonFunctions::type_name<Func_T>());
    CExtended_Function<Args...> res(func, func_name);

    return res;

其中type_name&lt;My_Function&gt;() 返回函数的名称为std::string_view

在 header.hpp 中定义

template <class T>
constexpr std::string_view type_name();

但是,当我像这样使用我的 make 函数时

在 source.cpp 中使用

static void Test_Callback();

auto test = Make_Extended_Function<Test_Callback>();

我收到了错误:

符号“Make_Extended_Function”无法解析

你能告诉我为什么会出现这个错误吗?

【问题讨论】:

你是众多尝试implement a template in a .cpp file的人之一吗? 不是所有模板都在头文件中定义和实现。 如果将所有内容放在一个文件中,问题会消失吗? 我写了这个作为答案,但后来我意识到这可能不是问题并删除了它。无论如何,您将函数作为类型参数传递,但它不是类型,请查看 godbolt.org/z/NnESxJ 。这是你想要达到的目标吗?如果你应用我的修复,它会编译吗? @L.F.不,这不是包含问题。 【参考方案1】:

您可能需要在代码中更改几件事:

    Test_Callback 是一个函数,您只能将函数指针作为非类型模板参数传递。 IE。它应该是auto test = Make_Extended_Function&lt;&amp;Test_Callback&gt;();; 如果你传递一个函数指针作为模板参数,语法是template&lt;function+pointer_type function pointer&gt;(类似于模板),所以make_extended_function应该是template <auto Func_T, typename... Args> CExtended_Function<Args...> Make_Extended_Function()(我在这里使用“auto”来使事情更容易)。 type_name() 也一样

示例代码:

#include <iostream>
#include <functional>
#include <string_view>

using namespace std;
namespace NCommonFunctions 
template <auto T>
std::string type_name()  return "a_name"; 

template <typename... Args>
class CExtended_Function

public:
    explicit CExtended_Function(
        const std::function<void(Args...)>& func_type, const std::string& func_name)
        : func(func_type)
        , function_name(func_name)
    
    

    /// Function
    const std::function<void(Args...)> func;

    /// Function Name
    const std::string function_name;
;

template <auto Func_T, typename... Args>
CExtended_Function<Args...> Make_Extended_Function()

    std::function<void(Args...)> func(Func_T);
    std::string func_name(NCommonFunctions::type_name<Func_T>());
    CExtended_Function<Args...> res(func, func_name);

    return res;

 void Test_Callback()  cout << "test" << endl; 
int main () 
    auto test = Make_Extended_Function<&Test_Callback>();
    test.func();

【讨论】:

【参考方案2】:

Make_Extended_Function 需要类型。你提供了函数指针,所以出错了。

更简单的解决方法可能是将Make_Extended_Function 更改为:

template <typename... Args>
CExtended_Function<Args...>
Make_Extended_Function(const std::function<void(Args...)>& f, const std::string& name)

    return CExtended_Function<Args...>(f, name);

(但您必须使用std::function 调用它才能允许扣除)。

NCommonFunctions::type_name 似乎与Make_Extended_Function 有相同的问题。

一个可能更好的解决方法是删除 std::function 并直接使用仿函数:

template <typename F>
class CExtended_Function

public:
    explicit CExtended_Function(
        const F& f, const std::string& name)
        : f(f)
        , name(name)
    
    

    F f;
    std::string name;
;

【讨论】:

以上是关于用函数名作为字符串将 std::function 包装在类中的主要内容,如果未能解决你的问题,请参考以下文章

第12课 std::bind和std::function_std::function可调用对象包装器

数组名作为函数参数.我编的这个错在那?

在python中获取函数名作为字符串[重复]

将二维数组名作为函数实参

C++ std::function怎么用

数组名作函数参数时,实参与形参变量之间的数据传递是?