decltype и оператор области видимости в C ++ - PullRequest
15 голосов
/ 15 февраля 2012

Мне нужно получить тип, который был указан при создании шаблона.Рассмотрим следующий пример:

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»: не является членом «глобального пространства имен»

Я собрал некоторую информацию по теме в Википедии:

Комментируя официальный проект Комитета для C ++ 0x, японский член ISO отметил, что «оператор области (: :) нельзя применить к decltype, но это так. Это было бы полезно в случаеполучить тип элемента (nested-type) из экземпляра следующим образом ": [16]

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

Этот и другие подобные вопросы были рассмотрены Дэвидом Вандевордом и утверждены в рабочем документе в марте 2010 года.

Поэтому я считаю, что в 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 ]

12 голосов
/ 15 февраля 2012

Это прозрачно заменяет ключевое слово 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 в свою реализацию стандартной библиотеки.

2 голосов
/ 15 февраля 2012

Обходной путь выглядит относительно хорошо, но он не расширяемый, а имена ужасные 1 . Почему бы не использовать id?

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

А потом:

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

Не проверено, но должно работать.


1 Как, например, слишком многословно, и хотя они описывают, что это обходной путь, это может быть излишним и не полезной информацией в большинстве ситуаций.

0 голосов
/ 15 февраля 2012

В качестве альтернативы вы можете легко вытащить тип с помощью помощника шаблона функции:

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();
}
...