我有以下代码:
enum RelationalOperator { LT, LTE, EQ, GTE, GT };
std::map<RelationalOperator, bool (*)(const Point&, const Point&)> ops = {
{ GTE, [](const Point& a, const Point& b) { return a >= b; } },
{ LTE, [](const Point& a, const Point& b) { return a <= b; } },
{ EQ, [](const Point& a, const Point& b) { return a == b; } },
{ GT, [](const Point& a, const Point& b) { return a > b; } },
{ LT, [](const Point& a, const Point& b) { return a < b; } },
};
此代码位于模板中,Point
是模板参数。
我尝试用ops
替换变量auto
的类型,但Clang ++说:
src/utils.hpp:47:10: error: cannot deduce actual type for variable 'ops' with type 'auto' from initializer list
为什么?我认为关键字auto
适用于这种情况,其中类型很长且相当明显。
答案 0 :(得分:5)
ALTER TABLE `tbl_name` ADD `cdate` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
不适用于初始化列表。可以使用相同的初始化列表初始化一堆其他类型,例如:
auto
答案 1 :(得分:4)
首先,每个lambda都有自己的类型,因此给定一组不同的lambda,如果没有一些手动转换(通常将它们嵌入std::function<R(Args...)>
个对象中),就不能将它们分解为单个类型。
然后,当你编写这样的初始化时:
enum RelationalOperator { LT, LTE, EQ, GTE, GT };
std::map<RelationalOperator, bool (*)(const Point&, const Point&)> ops = {
{ GTE, [](const Point& a, const Point& b) { return a >= b; } },
{ LTE, [](const Point& a, const Point& b) { return a <= b; } },
{ EQ, [](const Point& a, const Point& b) { return a == b; } },
{ GT, [](const Point& a, const Point& b) { return a > b; } },
{ LT, [](const Point& a, const Point& b) { return a < b; } },
};
真正发生了什么?它调用std::initializer_list
的{{1}}构造函数。它还能够推断出给定的支撑表达式是这种地图的初始化列表:
std::map<RelationalOperator, bool (*)(const Point&, const Point&)>
然后,你的lambda会发生隐式转换。
现在,如果你改写:
std::initializer_list<std::pair<RelationalOperator, bool (*)(Point const&, Point const&)>>
它无法确定支撑表达式(auto ops = {
{ GTE, [](const Point& a, const Point& b) { return a >= b; } },
{ LTE, [](const Point& a, const Point& b) { return a <= b; } },
{ EQ, [](const Point& a, const Point& b) { return a == b; } },
{ GT, [](const Point& a, const Point& b) { return a > b; } },
{ LT, [](const Point& a, const Point& b) { return a < b; } },
};
中的T
)表示的对象类型。这在gcc's error message中非常明确:
std::initializer_list<T>
答案 2 :(得分:3)
我认为关键字
auto
适用于这类情况,其中类型很长且相当明显。
类型并不明显。每个lambda表达式都会生成一个唯一的匿名闭包类型,因此初始化列表的每个元素都有不同的类型:
auto ops = {
{ GTE, lambda_type_1 },
{ LTE, lambda_type_2 },
{ EQ, lambda_type_3 },
{ GT, lambda_type_4 },
{ LT, lambda_type_5 },
};
每个支撑的初始化器没有任何共同之处。没有什么明显的。
初始化std::map
时,有一个构造函数使用std::initializer_list<value_type>
,编译器可以将每个初始值设定项转换为该类型。当您使用auto
替换地图时,编译器无法确定您希望从不相关类型列表中推断出哪种类型。
答案 3 :(得分:1)
还可以考虑使用std::equal_to
中可用的STL内置比较仿函数std::less_equal
,std::greater_equal
,std::less
,std::greater
和<functional>
头文件。
E.g:
#include <functional>
#include <map>
struct Point {
bool operator < (const Point &) const { /* actual implementation */ }
bool operator <= (const Point &) const { /* actual implementation */ }
bool operator > (const Point &) const { /* actual implementation */ }
bool operator >= (const Point &) const { /* actual implementation */ }
bool operator == (const Point &) const { /* actual implementation */ }
/* other stuff */
};
int main() {
enum RelationalOperator { LT, LTE, EQ, GTE, GT };
std::map<RelationalOperator, std::function<bool(const Point&, const Point&)>> ops = {
{GTE, std::greater_equal<Point>()},
{LTE, std::less_equal<Point>()},
{EQ, std::equal_to<Point>()},
{GT, std::greater<Point>()},
{LT, std::less<Point>()},
};
}