提问人:wcochran 提问时间:7/14/2023 最后编辑:JeJowcochran 更新时间:7/14/2023 访问量:99
如何在函数定义中定义和使用 std::less 作为模板参数?
How to define and use std::less as a template argument in a function definition?
问:
提供并用作模板参数的正确 C++ 语法是什么?std::less
#include <iostream>
#include <functional>
template<typename CMP>
float order(float a, float b)
{
return CMP(a, b) ? a : b; // COMPILE ERROR
// return CMP::operator()(a,b) ? a : b; // another try
// return (a CMP b) ? a : b; // ¯\_(ツ)_/¯
}
int main()
{
const float A = order<std::less<float>>(3.1, 7.2); // COMPILE ERROR
const float B = order<std::greater<float>>(3.1, 7.2);
std::cout << "A=" << A << "\n";
std::cout << "B=" << B << "\n";
return 0;
}
编译错误:
$ g++ -std=c++17 foo.cpp -o foo
foo.cpp:6:12: error: no matching constructor for initialization of 'std::__1::less<float>'
foo.cpp:12:21: note: in instantiation of function template specialization 'order<std::__1::less<float> >' requested here
const float A = order<std::less<float>>(3.1, 7.2);
^
答:
你可以像这样返回它:
return CMP{}(a,b) ? a : b;
这是因为 的构造函数不采用任何参数。std::less
CMP
是一个类型,因此您需要先创建此类型的对象 ,然后才能调用临时运算符进行比较。CMP{}
()
CMP
上述解决方案的作用是:它实例化一个对象,然后使用参数和 调用。然后,此运算符函数采用两个参数,如果是较小的参数,则返回 true(布尔表达式)。然后,通过三元检查,返回 和 之间的较小值。std::less
operator()
a
b
a
a
b
评论
提供并用作模板参数的正确 C++ 语法是什么?
std::less
or 是函子(即函数对象)。这意味着,在调用之前,您需要默认构造它们。因此,return 语句必须是std::less
std::greater
operator()
return CMP{}(a,b) ? a : b;
// ^^^^^^ ----> default construct the function object
但是,如果要保存一些键入,则可以对 .或者,您可以提供一个模板参数(即),以使其更通用(如果有意):order
typename T
template<template<typename> class CMP, typename T>
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --> template-template argument
constexpr auto order(T a, T b)
{
return CMP{}(a, b) ? a : b;
}
现在你把 asorder
const auto A = order<std::less>(3.1, 7.2);
// ^^^^^^^^^^^ -----> only specify the funnctor
const auto B = order<std::greater>(3.1, 7.2);
// ^^^^^^^^^^^^^^ --> only specify the funnctor
评论
设计良好的接口不会阻止使用有状态比较谓词。 而且,您可以免费获得其他替代方案的更好实现。
template<typename CMP> float order(float a, float b, CMP cmp = {}) {
return cmp(a, b) ? a : b;
}
注1:
尽管人们普遍认为,如果不能默认构造,语法仍然有效;但是,当然,您需要通过一种方法来构建它。
这很好。CMP
测试:
#include <iostream>
#include <functional>
template<typename CMP>
float order(float a, float b, CMP cmp = {}) {
return cmp(a,b) ? a : b;
}
template<class T>
struct LESS : std::less<T> {
LESS() = delete;
LESS(const char*) {}
};
int main() {
const float A = order<std::less <float>>(3.1, 7.2);
const float B = order<std::greater<float>>(3.1, 7.2);
const float C = order< LESS <float>>(3.1, 7.2, "less");
// const float D = order< LESS <float>>(3.1, 7.2); // compile error, good!
std::cout << "A=" << A << "\n";
std::cout << "B=" << B << "\n";
return 0;
}
注2:
设计得更好的界面将具有默认顺序:
template<typename CMP = std::less<float> >
float order(float a, float b, CMP cmp = {}) {
return cmp(a,b) ? a : b;
}
注3:
从技术上讲,如果类具有显式默认构造函数,则需要更详细的东西才能工作,但我不会以这种方式实现,因为如果默认构造函数是显式的,那么它必须有充分的理由,并且我们基本上是在覆盖类设计器的预期行为。
template<typename CMP = std::less<float> >
float order(float a, float b, CMP cmp = CMP{}) { // MMM, good idea?
return cmp(a,b) ? a : b;
}
奖金:
有些人(包括 STL、https://en.cppreference.com/w/cpp/algorithm/sort)不能容忍默认参数:
template<typename CMP>
float order(float a, float b, CMP cmp) {
return cmp(a,b) ? a : b;
}
template<typename CMP>
float order(float a, float b) {
return order<CMP>(a, b, {}); // or CMP{});
}
float order(float a, float b) {
return order<std::less<float>>(a, b);
}
评论
CMP
return CMP{}(a,b) ? a : b;
CMP(a,b)
template<typename CMP> float order(float a, float b, CMP cmp = {}) { return cmp(a,b) ? a : b; }
CMP