Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to circumvent Intel C++ compiler's issue with `decltype` and inheritance?

I was very surprised today to discover that Intel's icpc (version 14.0.2, using std=c++0x) fails to compile the following snippet.


#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)) {};

complaining about the last line:

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

The code works fine with clang and gcc.

I don't really fancy a complete re-write to make it work with flawed compilers (why is that always the commercial compilers are flawed?).

  • Is there a simpler way, than a completely different SFINAE pattern, to make it work with icc?

EDIT: Yes, I know that icc supports decltype since some time. But in the particular context above, icc fails to support it. Also note that using std=c++11 instead of std=c++0x makes no difference.

like image 804
Walter Avatar asked May 30 '14 09:05

Walter


2 Answers

As stated in the question, and comments, decltype has been supported in iccfor some time now; the problem is that it's not usable in every context because of a nasty bug in the compiler.


More specifically it cannot be used directly when specifying the base of a class, which requires us to write a workaround..

If we can't use it directly, let's use it indirectly (through an alias template)!


EXAMPLE WORKAROUND

template<class T>
using identity_hack = T;

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

Note: There are many variations to the above, one could for example use std::enable_if<true, decltype (...)>::type as an alternative if one doesn't want to declare something of their own.

like image 99
Filip Roséen - refp Avatar answered Nov 01 '22 12:11

Filip Roséen - refp


You can use a template based workaround - any of the standard types that take a template type argument and expose it as a typedef, then wrap that in a macro that's only defined for ICC e.g.

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

Which allows your example to compile without changes.

Once the bug is fixed in all versions of ICC you're using you can remove the macro definition without changing any other code.

(See this answer to a similar MSVC issue)

like image 3
JoeG Avatar answered Nov 01 '22 12:11

JoeG