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

时间:2012-02-15 10:06:48

标签: c++ scope c++11 operator-keyword decltype

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

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抱怨如下:

错误C2039:'TUnderlying':不是'`global namespace''的成员

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

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

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

David Vandevoorde提出了类似的问题,并于2010年3月投票进入了工作文件。

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

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

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

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

3 个答案:

答案 0 :(得分:12)

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

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

允许这样编译和使用MSVC10:

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

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

答案 1 :(得分:2)

解决方法看起来相对较好,但它不可扩展且名称很糟糕 1 。为什么不使用id

template <typename T>
struct id {
    typedef T type;
};

然后:

id<decltype(FooInt)>::type::TUnderlying;

未经测试,但应该有效。


1 因为过于冗长,即使他们描述这是一种解决方法,但在大多数情况下,这可能是多余的,而不是有用的信息。

答案 2 :(得分:0)

作为替代方法,您可以使用函数模板帮助程序轻松地拉出类型:

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

static Foo<int> FooInt;

template <typename T>
typename Foo<T>::TUnderlying foo_underlying(Foo<T> const &)
{
    return typename Foo<T>::TUnderlying();
}

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

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