decltype and the scope operator in C++

c++, c++11, decltype, operator-keyword, scope

Solution

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

Which allows this to compile and work on MSVC10:

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

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.

Problem

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; } ``` Problem with this code is using the scope operator together with decltype. Visual C++ 2010 complains like this: error C2039: 'TUnderlying' : is not a member of '`global namespace'' I gathered some information on the topic on Wikipedia: 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; ``` This, and similar issues were addressed by David Vandevoorde, and voted into the working paper in March 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?

Original source