Как обойти проблему компилятора Intel C++ с `decltype` и наследованием?

Сегодня я был очень удивлен, обнаружив, что Intel icpc (версия 14.0.2, использующая std=c++0x) не может скомпилировать следующий фрагмент.


#include <type_traits>

namespace traits_tests {
  template<typename>
  struct sfinae_true : std::true_type {};

  template<typename T>
  static auto value_type(int) -> sfinae_true<typename T::value_type>;
  template<typename T>
  static auto value_type(void*) -> std::false_type;
}

template<typename C>
struct has_value_type
  : decltype(traits_tests::value_type<C>(0)) {};

жалоба на последнюю строку:

inc/traits.h(258): error: expected an identifier
    : decltype(traits_tests::value_type<C>(0)) {};
      ^

Код отлично работает с clang и gcc.

Я действительно не хочу полностью переписывать, чтобы заставить его работать с дефектными компиляторами (почему коммерческие компиляторы всегда ошибочны?).

  • Есть ли более простой способ, чем совершенно другой шаблон SFINAE, заставить его работать с icc?

EDIT: Да, я знаю, что icc уже некоторое время поддерживает decltype. Но в приведенном выше конкретном контексте icc не поддерживает его. Также обратите внимание, что использование std=c++11 вместо std=c++0x не имеет значения.


person Walter    schedule 30.05.2014    source источник
comment
Не всегда коммерческие компиляторы имеют недостатки, просто люди пишут свой код на бесплатных компиляторах сначала, решая свои проблемы по ходу дела. ;-) Я уверен, что у пользователей компилятора Comeau будут выборочные слова для GCC, как только они обнаружат, что он не поддерживает export. ;-)   -  person DevSolar    schedule 30.05.2014
comment
Согласно их странице соответствия, decltype поддерживается начиная с v12, поэтому я нахожу это странным.   -  person WhozCraig    schedule 30.05.2014
comment
Возможно, отсутствует ключевое слово template — см. здесь — т. е. попробуйте decltype(template traits_tests::value_type<C>(0)) {};.   -  person Tony Delroy    schedule 30.05.2014
comment
@DevSolar, чтобы быть справедливым, IIRC export был лишь частично реализован одним Комо и был оставлен Комитетом мертвым как функция, потому что он просто не работал.   -  person Quentin    schedule 06.04.2017


Ответы (2)


Вы можете использовать обходной путь на основе шаблона - любой из стандартных типов, которые принимают аргумент типа шаблона и представляют его как typedef, а затем заключают его в макрос, определенный только для ICC, например.

#ifdef __INTEL_COMPILER
#include <utility>
#define decltype(...) \
  std::pair<decltype(__VA_ARGS__), int>::first_type
#endif

Что позволяет компилировать ваш пример без изменений.

Как только ошибка будет исправлена ​​во всех версиях ICC, которые вы используете, вы можете удалить определение макроса без изменения какого-либо другого кода.

(см. этот ответ на аналогичную проблему MSVC)

person JoeG    schedule 30.05.2014
comment
На самом деле я объединил это с ответом Филиппа. - person Walter; 30.05.2014
comment
@Walter Примечание: приведенное выше исправление нарушает [macro.names]p2 и делает программу неправильной. - person Filip Roséen - refp; 30.05.2014
comment
Здесь требуется определенный уровень прагматизма. Как показывает этот вопрос, сам компилятор неправильно реализует указанный вами стандарт, и я думаю, что выход за пределы стандарта для исправления поведения компилятора в этом случае является разумным компромиссом. - person JoeG; 30.05.2014
comment
@FilipRoséen-refp Да, но моя хорошо сформированная программа была отклонена. Я мог бы, конечно, последовать вашему предложению, но это означало отредактировать каждое вхождение decltype в таких обстоятельствах, чтобы сделать хорошо сформированный код чрезмерно сложным. - person Walter; 31.05.2014

Как указано в вопросе и комментариях, decltype уже некоторое время поддерживается в icc; проблема в том, что его нельзя использовать в каждом контексте из-за неприятной ошибки в компиляторе.


В частности, его нельзя использовать напрямую при указании базы класса, что требует от нас написания обходного пути.

Если мы не можем использовать его напрямую, давайте использовать его косвенно (через шаблон псевдонима)!


ПРИМЕР РЕШЕНИЯ

template<class T>
using identity_hack = T;

template<typename C>
struct has_value_type
  : identity_hack<decltype (traits_tests::value_type<C> (0))>
{ }

Примечание. Существует много вариантов вышеизложенного, например, можно использовать std::enable_if<true, decltype (...)>::type в качестве альтернативы, если вы не хотите объявлять что-то свое.

person Filip Roséen - refp    schedule 30.05.2014