【问题标题】:Template Parameter Pack Fails on Clang but not VS 2015模板参数包在 Clang 但不是 VS 2015 上失败
【发布时间】:2016-11-18 16:31:46
【问题描述】:

我正在开发一个函数,该函数使用可变数量的参数调用提供的函数。它在 Visual Studio 2015 上编译并正常工作,但在 Clang 上编译失败。我准备了一个演示,展示了我正在尝试做的事情。我在 Clang 中遇到的错误是:

prog.cpp:在函数“int main()”中:prog.cpp:31:2:错误:没有匹配 调用 'run(std::vector&, void ()(int&, const int&), const int&)' ); ^ prog.cpp:7:6: 注意:候选人: 模板无效 运行(std::vector&, const std::function&, mutrArgs ...) 无效运行( ^ prog.cpp:7:6:注意:模板参数推导/替换失败:prog.cpp:31:2:注意:不匹配的类型'const std::function' 和 'void ()(int&, const int&)');

#include <functional>
#include <iostream>
#include <vector>
using namespace std;

template<int RepeatTimes, class ... mutrArgs>
void run(
    vector<int>& vec,
    const function<void(int&, mutrArgs ...)>& mutr,
    mutrArgs ... args
)
{
    for (int times{0} ; times < RepeatTimes ; ++times)
        for (auto& item : vec)
            mutr(item, args...);
}

void adder(int& i, const int& val)
{
    i += val;
}

int main()
{
    vector<int> v{0,1,2,3,4,5,6,7,8,9};
    const int addValue{4};
    run<2, const int&>(
        v,
        &adder,
        addValue
    );
    for (auto i : v)
        cout << i << " ";
    cout << endl;
    return 0;
}

【问题讨论】:

  • 不要使用std::function,而是将类型也设为模板,就像所有standard algorithm functions一样。
  • 在非演示函数中,需要接受一定数量的参数。
  • 如果你使用std::function&lt;void(int&amp;,const int&amp;)&gt;(&amp;adder),它会编译。不知道为什么需要指定它。可能与不可扣除的包装部分有关,但我不确定规则。
  • 或者如果你通过函数指针传递run&lt;2, const int&amp;&gt;,它也可以工作Demo
  • 使用 std::function&lt;decltype(adder)&gt;(adder) 编译 clang++ 3.5 和 g++ 4.9.2

标签: c++ templates c++14


【解决方案1】:

run&lt;2, const int&amp;&gt; 只陈述第一个参数,但不禁用推论。

run<2, const int&>(v, &adder, addValue);

有2个地方可以推演mutrArgs

  • addValue -> mutrArgs = { const int&amp; }

  • &amp;adder 不是 std::function,因此失败。

获取函数地址修复该问题

auto call_run = &run<2, const int&>;
call_run(v, &adder, addValue);

奇怪的是,clang 不支持与 gcc 相反的内联用法:/

(&run<2, const int&>)(v, &adder, addValue);

如果你想禁用演绎,你可以让你的模板 arg 不可演绎:

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

template <typename T> using non_deducible_t = typename identity<T>::type;

然后

template<int RepeatTimes, class ... mutrArgs>
void run(
    std::vector<int>& vec,
    const std::function<void(int&, non_deducible_t<mutrArgs> ...)>& mutr,
    non_deducible_t<mutrArgs> ... args
)

Demo

即使在您的情况下,Joachim Pileborg 建议的简单 typename F 似乎更好。

【讨论】:

  • 为了让它最终在 clang 上正确编译,我需要同时做这两件事,获取函数地址并使用推导模板。
【解决方案2】:

如果您查看所有standard library algorithm function,至少那些采用“谓词”(可调用对象)的人将该参数作为模板类型。

如果你这样做,它会构建:

template<int RepeatTimes, typename F, class ... mutrArgs>
void run(
    vector<int>& vec,
    F mutr,
    mutrArgs ... args
)
{
    ...
}

here for an example of you code。请注意,您不需要提供所有模板参数,编译器可以推导出它们。

【讨论】:

  • 这绕过了所需的用法,当然可以。
猜你喜欢
  • 2014-06-29
  • 2021-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多