C++0x 编译器之间的 lambda 特征不一致
我观察到两个编译器(g++ 4.5、VS2010 RC)将 lambda 与类模板的部分特化相匹配的方式存在一些不一致。我试图为 lambda 实现类似 boost::function_types 的东西来提取类型特征。检查此了解更多详细信息。
在 g++ 4.5 中,lambda 的 operator()
的类型似乎类似于独立函数 (R (*)(...)),而在 VS2010 RC 中,它似乎是就像成员函数 (R (C::*)(...)) 一样。所以问题是编译器编写者可以自由地以他们想要的方式解释吗?如果不正确,哪个编译器是正确的?请参阅下面的详细信息。
template <typename T>
struct function_traits
: function_traits<decltype(&T::operator())>
{
// This generic template is instantiated on both the compilers as expected.
};
template <typename R, typename C>
struct function_traits<R (C::*)() const> { // inherits from this one on VS2010 RC
typedef R result_type;
};
template <typename R>
struct function_traits<R (*)()> { // inherits from this one on g++ 4.5
typedef R result_type;
};
int main(void) {
auto lambda = []{};
function_traits<decltype(lambda)>::result_type *r; // void *
}
该程序可在 g++ 4.5 和 VS2010 上编译,但实例化的 function_traits 与代码中所述不同。
I observed some inconsistency between two compilers (g++ 4.5, VS2010 RC) in the way they match lambdas with partial specializations of class templates. I was trying to implement something like boost::function_types for lambdas to extract type traits. Check this for more details.
In g++ 4.5, the type of the operator()
of a lambda appears to be like that of a free standing function (R (*)(...)) whereas in VS2010 RC, it appears to be like that of a member function (R (C::*)(...)). So the question is are compiler writers free to interpret any way they want? If not, which compiler is correct? See the details below.
template <typename T>
struct function_traits
: function_traits<decltype(&T::operator())>
{
// This generic template is instantiated on both the compilers as expected.
};
template <typename R, typename C>
struct function_traits<R (C::*)() const> { // inherits from this one on VS2010 RC
typedef R result_type;
};
template <typename R>
struct function_traits<R (*)()> { // inherits from this one on g++ 4.5
typedef R result_type;
};
int main(void) {
auto lambda = []{};
function_traits<decltype(lambda)>::result_type *r; // void *
}
This program compiles on both g++ 4.5 and VS2010 but the function_traits that are instantiated are different as noted in the code.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我认为 GCC 不合规。N3092 §5.1.2/5 说因此,虽然有关闭包对象类型的许多内容都是实现定义的,但函数本身必须是
public
的成员,并且必须是const
的非静态成员。编辑:该程序表明
operator()
是GCC 4.6上的成员函数,本质上与4.5相同。输出:
编辑: 看起来唯一的问题是指向某些闭包调用运算符的指针无法匹配 ptmf 模板模式。解决方法是声明 lambda 表达式
可变
。如果没有捕获,并且仅(除了解决问题之外)似乎改变了调用运算符的常量性,那么这是毫无意义的。输出:
如果没有 mutable 且使用 const,spectfun 不会打印最后两个查询中任何一个的签名。
I believe that GCC is noncompliant.N3092 §5.1.2/5 saysSo while many things about the closure object's type are implementation-defined, the function itself must be a member to be
public
and must be a nonstatic member to beconst
.EDIT: This program indicates that
operator()
is a member function on GCC 4.6, which is essentially the same as 4.5.output:
EDIT: It looks like the only problem is that pointers to certain closure call operators fail to match ptmf template patterns. The workaround is to declare the lambda expression
mutable
. This is meaningless if there is no capture and only (aside from fixing the problem) seems to change the const-ness of the call operator.output:
Without the mutable and with the const,
spectfun
does not print signatures for either of the last two queries.阅读n3043。 Lambda 现在可以转换为函数指针,前提是它们没有任何状态。我相信(...但不知道)GCC 最初意外地实现了此行为,“修复了它”,现在将其重新添加到 4.5 或 4.6。 VC10 按照最初设计正确实现了 lambda,但不符合 n3043 的最新工作文件。
Read n3043. Lambdas are now convertible to function pointers provided they don't have any state. I believe (...but do not know) GCC initially implemented this behavior accidentally, "fixed it", now will be re-adding it to 4.5 or 4.6. VC10 implemented lambdas correctly as initially designed, but not conforming to the latest working papers with n3043.
我认为 gcc 开发人员的这种行为是有充分理由的。请记住,静态函数没有“this”指针,并且当实际调用它时,调用者不需要传递“this”指针。因此,当闭包对象中实际上不包含任何内容时,这是一个小的性能优化。您可以看到 G++ 开发人员通过将 lambda 表达式声明为“可变”(记住您实际上没有任何内容可以改变)为您提供了一种解决方法。
I think gcc developers has a good reason for this behaivor. Remember, a static function do not have a "this" pointer, and when it is being actually called, the caller do not required to pass the "this" pointer. So this is a small performance optimisation when it is actually nothing contained in the closure object. And you can see the G++ developer leave you a way to workaround by declaring the lambda expression as "mutable" (remember you actually do not have anything to mutate).