首页 > 解决方案 > 在参数推导过程中,泛型 lambda、模板函数和模板成员 operator() 之间的主要区别是什么?

问题描述

与算法一起使用时,我对以下差异感到困惑。

首先,算法可以毫无问题地使用 lambda、函数和仿函数。例如,

bool comp (int t1, int t2) {
    return t1 > t2;
}
std::array<int, 10> myArray{5, -10, 3, 2, 7, 8, 9, -4, 3, 4};
std::sort(myArray.begin(), myArray.end(), comp);

现在让我们定义模板比较器,

template<typename T>
bool comp1(T t1, T t2) {
    return t1 > t2;
}

struct Comp {
    template<typename T>
    bool operator()(T t1, T t2) const {
        return t1 > t2;
    }
};
Comp comp2;

auto comp3 = [](auto t1, auto t2) { return t1 > t2; }


template<typename Container>
void sortDescending(Container &c) {
    std::sort(c.begin(), c.end(), comp1); // cannot deduce argument error
    std::sort(c.begin(), c.end(), comp2); // works
    std::sort(c.begin(), c.end(), comp3); // works
}

sortDescending(myArray);

函数模板在上述场景中不起作用,这让我很困惑。

对我来说,至少 comp1 和 comp2 几乎相同(在某种意义上,推断参数所需的信息量)。但是 comp1 不起作用。

所以我的问题是,这种差异背后的最终原因是什么?

即,就参数推导而言,函数模板、模板 operator()(模板仿函数?)和通用 lambda 之间的主要区别是什么?

谢谢。

标签: c++templatesc++14

解决方案


模板是 C++ 的一种语言构造,它生成其他构造:类、函数或变量(在 C++14 中)。没有模板参数的模板名称只能以非常有限的方式使用。

comp1命名模板,而不是函数。这是重要的一点。函数模板是在您提供特定模板参数时生成函数的构造;comp1<int>是函数的名称。但名称本身命名模板,而不是它生成的函数。

函数模板的名称可以被调用(即:)comp1(arg1, arg2),因为 C++ 的一个特殊规则称为“模板参数推导”。简而言之,编译器根据提供给函数调用的参数comp的声明comp和性质推断模板参数的类型。但这仅有效,因为 C++ 有一条规则表明它确实有效。

单独的模板名称(如comp1)不是表达式,函数调用期望表达式(或花括号初始化列表)作为参数给出。错误“无法推断参数错误”不是关于 std::sort; 这是关于为 自己推断模板参数std::sortcomp1,一个模板,没有类型,所以它不能参与参数推导。

comp2命名一个变量,就像comp3. 这两个都是表达式,所以都可以传递给函数。

是的,两者的类型都comp2包含comp3 一个函数模板。但是comp2comp3 作为名称命名变量,而不是它们包含的函数模板。所以它们像任何其他变量一样工作。

至于泛型 lambda,它与任何其他具有模板方法的用户定义类型没有什么不同。operator()


推荐阅读