【问题标题】:Why does std::function not work with function templates?为什么 std::function 不适用于函数模板?
【发布时间】:2021-09-16 20:08:37
【问题描述】:

我开始使用模板,并试图找出以下不起作用的原因。

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&lt;std::string, double&gt;(some_function); 这实际上是我想做的,因为它的样板要少得多,而且我不希望 testclass1 需要模板参数。

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

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

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

我不明白附加的“type-parameter-0-0”是什么。直观地说,这看起来很像链接到隐式 *this 指针的问题,但我不明白为什么 TFunc 会是成员函数并具有隐式 *this 指针(或者 this 是否链接到 std::function?)。此外,将代码 template &lt;typename...Ts&gt; using TFunc = std::function&lt;void(Ts*...)&gt;; 移出 testclass1 不会改变任何内容。

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

有没有办法让tc1.SetFunction&lt;std::string, double&gt;(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,并推导出了双精度数(因此并非所有参数都在包中指定)。但是为什么它在这种情况下有效并且我没有收到错误消息?

【问题讨论】:

    标签: c++ templates


    【解决方案1】:

    您似乎不能将std::function 与模板函数一起使用

    不,这个问题与std::function无关。

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

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

    但如果是包装,则总是会执行扣除。这是因为可以指定 一些 包参数并让编译器推导出其余的参数,并且无法知道您是仅指定了部分参数还是所有参数。

    但是std::function&lt;void(std::string*, double*)&gt;不能从void(*)(std::string*, double*)推导出来(推导时不考虑用户自定义的转换)。因此错误:

    template argument deduction/substitution failed:
    mismatched types 'std::function&lt;void(Ts* ...)&gt;' 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是一个类,它可以由一个函数指针构造出来,但是这些是不同的类型,所以不能从另一个推导出来。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-15
      • 2012-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多