C++ 中的 decltype 和作用域运算符

2022-01-04 00:00:00 scope operator-keyword c++ c++11 decltype

我需要获取实例化模板时提供的类型.考虑以下示例:

I need to obtain the type which was supplied when instantiating a template. Consider the following example:

template <typename T> struct Foo
{
  typedef T TUnderlying;
};

static Foo<int> FooInt;

class Bar
{
public:
  auto Automatic() -> decltype(FooInt)::TUnderlying
  {
    return decltype(FooInt)::TUnderlying();
  }
};

int main()
{
  Bar bar;
  auto v = bar.Automatic();
    return 0;
}

此代码的问题是将作用域运算符与 decltype 一起使用.Visual C++ 2010 抱怨如下:

Problem with this code is using the scope operator together with decltype. Visual C++ 2010 complains like this:

错误 C2039:TUnderlying":不是全局命名空间"的成员

error C2039: 'TUnderlying' : is not a member of '`global namespace''

我在维基百科上收集了一些关于该主题的信息:

I gathered some information on the topic on Wikipedia:

在评论 C++0x 的正式委员会草案时,日本 ISO 成员团体指出范围运算符 (::) 不能应用于 decltype,但它应该适用.这在以下情况下很有用从实例中获取成员类型(嵌套类型),如下所示":[16]

While commenting on the formal Committee Draft for C++0x, the Japanese ISO member body noted that "a scope operator(::) cannot be applied to decltype, but it should be. It would be useful in the case to obtain member type(nested-type) from an instance as follows":[16]

vector<int> v;
decltype(v)::value_type i = 0; // int i = 0;

David Vandevoorde 解决了这个问题和类似问题,并于 2010 年 3 月投票通过了工作文件.

This, and similar issues were addressed by David Vandevoorde, and voted into the working paper in March 2010.

所以我认为 Visual C++ 2010 没有实现这个.我想出了这个解决方法:

So I reckon the Visual C++ 2010 does not have this implemented. I came up with this workaround:

template <typename T> struct ScopeOperatorWorkaroundWrapper
{
  typedef typename T::TUnderlying TTypedeffedUnderlying;
};

auto Automatic() -> ScopeOperatorWorkaroundWrapper<decltype(FooInt)>::TTypedeffedUnderlying
{
  return ScopeOperatorWorkaroundWrapper<decltype(FooInt)>::TTypedeffedUnderlying();
}

我是否错过了任何更优雅、更简洁的解决方案?

Did I miss any solution which is more elegant and less verbose?

推荐答案

这透明地用基于模板的解决方法替换了 decltype 关键字.一旦您不再需要支持 MSVC2010,您就可以在不更改任何用户代码的情况下删除宏定义:

This transparently replaces the decltype keyword with the template based workaround. Once you no longer need to support MSVC2010 you can remove the macro definition without changing any user code:

#if _MSC_VER == 1600
#include <utility>
#define decltype(...) 
  std::identity<decltype(__VA_ARGS__)>::type
#endif

这允许它在 MSVC10 上编译和工作:

Which allows this to compile and work on MSVC10:

std::vector<int> v;
decltype(v)::value_type i = 0;

<小时>

请注意,std::identity 不是 C++ 标准的一部分,但在这里依赖它是安全的,因为解决方法仅限于包含 std::identity 的编译器 在其标准库实现中.


Note that std::identity isn't part of the C++ standard, but it's safe to rely on it here as the workaround is limited to a compiler which includes std::identity in its standard library implementation.

相关文章