c++ 11对std::greater和std::less的条件表达式得到了不同类型的错误
C++11 conditional expression on std::greater and std::less got error of different types
与条件表达式相关的代码如下:
typedef unsigned char uchar;
uchar data[100];
// assign something to array[] here
uchar *start = data;
uchar *end = data+100;
bool cond = f(); // f() could return true or false
uchar *itr = std::upper_bound(start, end, uchar(20),
cond? std::greater<uchar>() : std::less<uchar>());
出现如下错误:
error: operands to ?: have different types
‘std::greater<unsigned char>’ and ‘std::less<unsigned char>’
这是一个编译器错误吗?根据我的直觉,这两个函子应该具有相同的类型。
std::greater
和std::less
是不同的类型(就像std::string
和std::unordered_map
一样)。它们只提供相同的接口(operator()
)。
条件运算符cond ? expr1 : expr2
要求expr1
和expr2
是同一类型(或者一个可以隐式转换为另一个),而这不是您的情况。
可以使用
char *itr;
if (cond)
itr = std::upper_bound(start, end, uchar(20), std::greater<uchar>{});
else
itr = std::upper_bound(start, end, uchar(20), std::less<uchar>{});
或者,如果你不想有几乎相同的两行,你可以帮助自己使用泛型lambda
auto upper_bound = [&](const auto& cmp){
return std::upper_bound(start, end, uchar(20), cmp);
};
if (cond)
itr = upper_bound(std::greater<uchar>{});
else
itr = upper_bound(std::less<uchar>{});
c++中的函子传统上不共享类型。这使得编译器很容易理解确切地是哪个函函数被调用,并导致性能提升。
在c++中有一种叫做类型擦除的机制。在这里,您忘记了使两种类型不同的原因,而只记得使它们相同的原因。 c++中最常见的类型擦除是std::function
。这里的函数类型擦除一个无状态模板,该模板接受两个T const&
并返回一个bool
:
template<class T, template<class...>class Z>
std::function< bool(T const&, T const&) >
comp() { return Z<T>{}; }
我们可以把你的代码,并这样做:
uchar *itr = std::upper_bound(start, end, uchar(20),
cond? comp<uchar, std::greater>() : comp<uchar, std::less>());
或者:
template<class T>
using comp_sig = bool(T const&, T const&);
template<class T, template<class...>class Z>
comp_sig<T>* comp() {
return [](T const& lhs, T const& rhs)->bool{
return Z<T>{}(lhs, rhs);
};
}
为您提供了根据需要调用less
或greater
的函数指针。对于编译器来说,这个版本可能比std::function
版本更容易优化,因为编译器非常擅长优化常量函数指针。
函子只是常规类型。std::greater<uchar>
与std:less<uchar>
是完全不同的类型。就像std::vector<uchar>
不同于std::set<uchar>
一样,尽管它们的属性相似!
你可以实现你想要实现的,如果你移动你的三元操作符:
char *itr = cond ?
std::upper_bound(start, end, uchar(20), std::greater<uchar>()) :
std::upper_bound(start, end, uchar(20), std::less<uchar>());
它稍微多了一些重复,但是同样可读并且可以编译。
我认为不是,因为它是不同的类型。Std::less是这样的:
template <class T>
struct Less
{
bool operator()(const T & t1, const T & t2) ..
};
首先,这两个函函数不具有相同的类型,尽管它们具有相同类型的操作符(),即在模板实例化之后,
bool operator()(uchar lhs, uchar rhs)
同样,仅仅因为vector<int>
和deque<int>
具有相同类型的操作符[]显然并不意味着它们具有相同的类型。
回到你的代码,如果你能使用c++ 11,一个简单的&优雅的解决方案是使用lambda:
char *itr = std::upper_bound(start, end, uchar(20),
[cond](uchar lhs, uchar rhs) { return cond ? lhs > rhs : lhs < rhs); }
否则,就直接写一个函子
class F{
public:
explicit F(bool cond): m_cond(cond) {}
bool operator(uchar lhs, uchar rhs) { return m_cond ? lhs > rhs : lhs < rhs); }
private:
bool m_cond;
};
最后,lambda是一个非常方便的工具,我建议你多了解它。
c++ 11中的lambda表达式是什么?
何时在lambda
将它们都转换为lambdas(非捕获,非泛型)。在这种情况下,它们的类型仍然不同,但它们都自然地转换为普通的旧函数指针bool (*) (uchar, uchar)
,因此?:
可以工作
uchar *itr = std::upper_bound(start, end, uchar(20),
cond?
([](uchar x, uchar y){return std::greater<uchar>{}(x,y);})
:
([](uchar x, uchar y){return std::less <uchar>{}(x,y);})
);
(这在clang 3.5和g++ 5.3上适用,但我不确定它的可移植性如何。我应该使用一元+
强制转换到函数指针吗?
- 使用std::source_location报告错误的最佳实践
- std::is_base_of表示ctor编译错误
- 多个文件的内存分配错误"在抛出 'std :: bad_alloc' what (): std :: bad_alloc 的实例后终止调用" [C++]
- 程序崩溃并显示"std::out_of_range"错误
- 在c++中尝试对对象数组进行排序时,出现std:bad_alloc错误
- 我收到以下错误:抛出'std::bad_alloc'实例后终止调用
- 尝试使用 std::vector<std::thread时出现静态断言失败错误>
- 错误 C2679:二进制"<<":未找到采用类型 'std::string_view' 的右侧操作数的运算符(或者没有可接受的转换)
- 为什么 std::绑定错误参数可以成功?
- std::cout输出int时出现编译错误
- 使用静态库与 std::jthread (g++-10) 的分段错误
- std::unordered_map 类型对象声明期间出现"field has incomplete type"错误
- 在缺少函数重载时抛出异常,并带有 std::variant 而不是编译时错误
- 使用 memcpy() 复制到 std::chrono::milliseconds 会给出错误 -Werror=clas
- 显式 std::exception_ptr 转换为 bool 不存在.VS2010 错误?
- "random_shuffle":不是"std"错误的成员
- VC++ 2010 "array is not a member of std"错误
- 开发C++ "to_string is not a member of std"错误
- STD未来异常-已检索,STD错误
- 交叉编译c++的树莓派std错误