lambda traits在C++ 0x编译器中的不一致性

Sum*_*ant 15 c++ lambda traits c++11

我发现两个编译器(g ++ 4.5,VS2010 RC)之间存在一些不一致的方式,它们将lambdas与类模板的部分特化相匹配.我试图为lambdas实现类似boost :: function_types的东西以提取类型特征.请查看此内容以获取更多详

在g ++ 4.5中,operator()lambda 的类型看起来像一个独立函数(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 *
}
Run Code Online (Sandbox Code Playgroud)

这个程序在g ++ 4.5和VS2010上编译,但实例化的function_traits是不同的,如代码中所述.

Pot*_*ter 3

我认为 GCC 不合规。N3092 \xc2\xa75.1.2/5 说

\n\n
\n

lambda 表达式的闭包类型具有公共内联函数调用运算符 (13.5.4),其参数和返回类型由 lambda 表达式\xe2\x80\x99s\n 描述分别为参数声明子句和\n 尾随返回类型。\n 当且仅当\n lambda 表达式\xe2\x80\x99s\n 参数时,此函数调用运算符\n 被声明为const (9.3.1) -declaration-clause 后面不是可变的。

\n
\n\n

因此,虽然关于闭包对象类型的许多事情都是实现定义的,但函数本身必须是 be 的成员,public并且必须是非静态成员const

\n\n

编辑:该程序表明这operator()是 GCC 4.6 上的成员函数,本质上与 4.5 相同。

\n\n
#include <iostream>\n#include <typeinfo>\nusing namespace std;\n\ntemplate< class ... > struct print_types {};\n\ntemplate<> struct print_types<> {\n friend ostream &operator<< ( ostream &lhs, print_types const &rhs ) {\n  return lhs;\n }\n};\n\ntemplate< class H, class ... T > struct print_types<H, T...> {\n friend ostream &operator<< ( ostream &lhs, print_types const &rhs ) {\n  lhs << typeid(H).name() << " " << print_types<T...>();\n  return lhs;\n }\n};\n\ntemplate< class T >\nstruct spectfun {\n friend ostream &operator<< ( ostream &lhs, spectfun const &rhs ) {\n  lhs << "unknown";\n  return lhs;\n }\n};\n\ntemplate< class R, class ... A >\nstruct spectfun< R (*)( A ... ) > {\n friend ostream &operator<< ( ostream &lhs, spectfun const &rhs ) {\n  lhs << "returns " << print_types<R>()\n   << " takes " << print_types<A ...>();\n  return lhs;\n }\n};\n\ntemplate< class C, class R, class ... A >\nstruct spectfun< R (C::*)( A ... ) > {\n friend ostream &operator<< ( ostream &lhs, spectfun const &rhs ) {\n  lhs << "member of " << print_types<C>() << ", " << spectfun<R (*)(A...)>();\n  return lhs;\n }\n};\n\ntemplate< class T >\nstruct getcall {\n typedef decltype(&T::operator()) type;\n};\n\nint main() {\n int counter = 0;\n\n auto count = [=]( int ) mutable { return ++ counter; };\n\n cerr << spectfun< getcall<decltype(count)>::type >() << endl;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

输出:

\n\n
member of Z4mainEUlvE_, returns i takes i\n
Run Code Online (Sandbox Code Playgroud)\n\n

编辑:看起来唯一的问题是指向某些闭包调用运算符的指针无法匹配 ptmf 模板模式。解决方法是声明 lambda 表达式mutable。如果没有捕获,并且仅(除了解决问题之外)似乎改变了调用运算符的常量性,那么这是毫无意义的。

\n\n
template< class T >\nstruct getcall {\n    typedef decltype(&T::operator()) type;\n    static type const value;\n};\ntemplate< class T >\ntypename getcall<T>::type const getcall<T>::value = &T::operator();\n\nint main() {\n    auto id = []( int x ) mutable { return x; };\n    int (*idp)( int ) = id;\n    typedef decltype(id) idt;\n    int (idt::*idptmf)( int ) /* const */ = getcall< decltype(id) >::value;\n\ncerr << spectfun< decltype(idp) >() << endl;\ncerr << spectfun< decltype(idptmf) >() << endl;\ncerr << spectfun< getcall<decltype(id)>::type >() << endl;\n
Run Code Online (Sandbox Code Playgroud)\n\n

输出:

\n\n
returns i takes i \nmember of Z4mainEUliE0_ , returns i takes i \nmember of Z4mainEUliE0_ , returns i takes i \n
Run Code Online (Sandbox Code Playgroud)\n\n

不带 mutable 且带 const 时,spectfun不会打印最后两个查询中任何一个的签名。

\n