C++ 可变参数模板:gcc 和 nvcc/intel 中的不同优先级

C++ variadic template: different priorities in gcc and nvcc/intel

下一个代码有问题:

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

template<typename... Args>
inline double foo(function<double (Args...)> fun, Args... args) {
    return fun(args...);
}

template<typename... Args, typename... ArgsTmp>
double foo(function<double (Args...)> fun, ArgsTmp... args) {
    return foo(fun, 1., args...);
}

int main() {

    function<double (double, double, double)> fun = [&](double x, double y, double z) -> double {
        return x+y+z;
    };

    cout << foo(fun) << endl;
}

当我用 gcc 编译它时一切正常。但是,如果我尝试编译它,例如,使用 intel 或 nvcc-7.5(这实际上是我的目标),我会收到以下错误:

more than one instance of overloaded function "foo" matches the argument list:
            function template "double foo(std::vector<limits, std::allocator<limits>>, std::function<double (Args...)>, Args...)"
            function template "double foo(std::vector<limits, std::allocator<limits>>, std::function<double (Args...)>, ArgsTmp...)"
            argument types are: (std::vector<limits, std::allocator<limits>>, std::function<double (double, double, double)>, double, double, double)
...
1 error 

有什么方法可以让编译器明确知道当 Args==ArgsTmp(在第二个模板中)时,应该拒绝 foo() 的以下实施?

你可以试试 SFINAE 和 enable_if

template<typename... Args, typename... ArgsTmp>
std::enable_if_t<!std::is_same<std::tuple<Args...>,
                               std::tuple<ArgsTmp...>>::value,
                 double>
foo(function<double (Args...)> fun, ArgsTmp... args) {
    return foo(fun, 1., args...);
}

你可以考虑参数个数:

#include <iostream>
#include <functional>
#include <type_traits>

template<typename... Args>
inline double foo(std::function<double (Args...)> fun, Args... args) {
    return fun(args...);
}

// Only considered, if the number of arguments is less than the number
// of expected arguments (accepting any number of arguments may lead 
// to infinite recursion).
template<typename... Args, typename... ArgsTmp>
inline typename std::enable_if<sizeof...(ArgsTmp) < sizeof...(Args), double>::type
foo(std::function<double (Args...)> fun, ArgsTmp... args) {
    return foo(fun, 1., args...);
}

int main()
{
    // A shorter variant
    std::function<double (double)> fun = [&](double x) -> double {
        return x;
    };
    std::cout << foo(fun) << std::endl;
    std::cout << foo(fun, 2.0) << std::endl;
    // error: no matching function for call to ‘foo(std::function<double(double)>&, double, double)’
    // std::cout << foo(fun, 3.0, 4.0) << std::endl;
}