c++ - 为什么 std::function 不能与函数模板一起使用?

标签 c++ templates

我开始使用模板,并试图找出为什么以下内容不起作用。

class testclass1
{
public:
    
    template <typename...Ts>
    using TFunc = std::function<void(Ts*...)>;
    
    template <typename...Ts>
    void SetFunction(TFunc<Ts...> tf)
    {
        // Do something
    }
};

template<typename...Ts>
class testclass2
{
public:
    
    using TFunc = std::function<void(Ts*...)>;
    
    void SetFunction(TFunc tf)
    {
        // Do something
    }
};

void some_function(std::string*, double*)
{
    
}

int main()
{
    
    testclass1 tc1;
    testclass2<std::string, double> tc2;
    
    testclass1::TFunc<std::string, double> tf1 = some_function;

    tc1.SetFunction<std::string, double>(tf1);
    tc1.SetFunction<std::string, double>(testclass1::TFunc<std::string, double>{tf1});
    
    tc2.SetFunction(some_function);
    
    tc1.SetFunction<std::string, double>(some_function);
}

除了最后一个版本外,一切正常 tc1.SetFunction<std::string, double>(some_function); 这实际上是我想做的,因为它的样板要少得多,而且我不希望 testclass1 需要模板参数。

最后一行给出以下编译错误:

没有匹配的成员函数来调用“SetFunction”

  1. 候选模板被忽略:无法将“function...)>”与“void ()(std::__1::basic_string *, double *)'

我不明白附加的“type-parameter-0-0”是什么。直观上,这看起来很像链接到隐式 *this 指针的问题,但我不明白为什么 TFunc 会是一个成员函数并且有一个隐式 *this 指针(或者 this 链接到 std::function 吗?)。另外,移动代码 template <typename...Ts> using TFunc = std::function<void(Ts*...)>; testclass1 之外不会改变任何内容。

通过浏览不同的相关问答,似乎您不能将 std::function 与模板函数一起使用。这是这里的问题吗?

有没有办法制作 tc1.SetFunction<std::string, double>(some_function);在 testclass1 中工作?

提前致谢。

更新:我正在努力理解这个解释,我想我有点明白了,但是想想——我仍然不是 100% 确定。考虑以下代码:

template <typename...Ts>
using test_tuple = std::tuple<Ts...>;

template <typename...Ts>
void test_func(test_tuple<Ts...> tup)
{
    // Do something
    // e.g., PrintTuple(tup);
}

int main()
{
    test_tuple<std::string, double> tt{"Hi", 3.1459f};
    test_func<std::string>(tt);
}

在这种情况下,只有std::string在参数包中指定并推导 double(因此并非所有参数都在包中指定)。但为什么它在这种情况下有效并且我没有收到错误?

最佳答案

it seems that you cannot use std::function with template functions

不,该问题与 std::function 无关.

问题是 template parameter pack 推演失败。通常,当您显式指定所有模板参数时,不会执行任何推导。

    tc1.SetFunction<std::string, double>(some_function); // no deduction needed, right?

但如果是,则总是执行扣除。这是因为可以指定一些包参数并让编译器推断其余的参数,并且无法知道您是否只指定了部分或全部参数。

但是std::function<void(std::string*, double*)>无法从 void(*)(std::string*, double*) 推出(并且在推导过程中不考虑用户定义的转换)。因此出现错误:

template argument deduction/substitution failed:
mismatched types 'std::function<void(Ts* ...)>' and 'void (*)(std::string*, double*)'

(注意 - GCC 11 output 中没有提及“type-parameter-0-0”,因此您的编译器可能已过时)。

现在,为了解决这个问题,我们可以向 SetFunction 的参数引入非推导的上下文。 。然后将从提供的类型参数执行替换。

例如使用身份模板:

template<typename T>
struct type_identity {
    using type = T;
};

class testclass1
{
public:
    
    template <typename...Ts>
    using TFunc = std::function<void(Ts*...)>;

    template <typename...Ts>
    void SetFunction(typename type_identity<TFunc<Ts...>>::type tf)
    {
        // Do something
    }
};

( Live demo )


关于更新及后续问题-test_tuple参数很高兴地从 test_tuple 中推导出来。参数 - 不涉及转换,只是模式匹配。但是std::function是一个类,它可以从函数指针构造,但它们是不同的类型,因此不能从另一个推断出一个。

关于c++ - 为什么 std::function 不能与函数模板一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69214574/

相关文章:

c++ - 如何制作一个 C++ 模板类,根据模板值的类更改其成员和访问器?

c++ - 有效使用 enable_if 和 C++ 模板来避免类特化

c++ - std::remove_if 中的 const 参数

c++ - 不同地方的段错误

c++ - 两个不完全相同的函数指针是否兼容?

c++ - 当我将它添加到指针时,我可以安全地忽略溢出检查的最小偏移量是多少?

c++ - Std::Array with unique_ptr

ruby-on-rails - Rails JS 响应,同时呈现状态和模板?

c++ - 如何在函数导出上运行清理代码?

C++ 模板类继承[无法转换模板]