关于c ++:模板参数包在Clang上失败但在VS 2015上失败

Template Parameter Pack Fails on Clang but not VS 2015

我正在处理一个函数,它用变量数的参数调用一个提供的函数。它在Visual Studio 2015上编译并正常工作,但未能在Clang上编译。我准备了一个演示,展示我正在做什么。我遇到的错误是:

prog.cpp: In function 'int main()': prog.cpp:31:2: error: no matching
function for call to 'run(std::vector&, void ()(int&, const
int&), const int&)' ); ^ prog.cpp:7:6: note: candidate:
template void
run(std::vector&, const std::function&,
mutrArgs ...) void run(
^ prog.cpp:7:6: note: template argument deduction/substitution failed: prog.cpp:31:2: note: mismatched types 'const
std::function' and 'void ()(int&, const
int&)' );

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#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;
}


run<2, const int&>只说明第一个参数,但不取消演绎。

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

有2个地方可以推断mutrArgs

  • addValue->mutrArgs={ const int& }

  • &adder,不是std::function,所以失败了。

解决这个问题

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

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

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

如果要禁用扣除,可以使模板arg不可扣除:

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

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

然后

1
2
3
4
5
6
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
)

演示

即使在你的例子中,约阿希姆·皮尔伯格建议的一个简单的typename F似乎更好。


如果您查看所有标准库算法函数,至少那些采用"谓词"(可调用对象)的函数,它们将该参数作为模板类型。

如果您这样做,它将生成:

1
2
3
4
5
6
7
8
9
template<int RepeatTimes, typename F, class ... mutrArgs>
void run(
    vector<int>& vec,
    F mutr,
    mutrArgs ... args
)
{
    ...
}

有关代码的示例,请参见此处。注意,您不需要提供所有模板参数,编译器可以推断出它们。