Intel® C++ Compiler
Community support and assistance for creating C++ code that runs on platforms based on Intel® processors.
7957 Discussions

valid code corrupts compiler and causes bug in template deduction

rnickb
Beginner
289 Views

The following code below works fine in clang or gcc, but fails with intel compiler 2016.

Note if you comment out the section of code labeled block A (which has nothing to do with anything and isn't referenced) the code compiles. It seems that somehow it's corrupting icc. Please suggest a work around and let me know when you have a patch available.

#include <type_traits>

template <bool... Values>
struct And {
  static constexpr bool value = true;
};

template <bool ValueFirst, bool... ValuesRest>
struct And<ValueFirst, ValuesRest...> {
  static constexpr bool value = ValueFirst && And<ValuesRest...>::value;
};

class Concept {
 protected:
  // list
  template <bool... Values>
  using list = std::integral_constant<bool, And<Values...>::value>;

  // valid
  template <class T>
  static constexpr bool valid() {
    return true;
  }

  // same
  template <class A, class B>
  static constexpr bool same() {
    return std::is_same<A, B>();
  }

  // convertible
  template <class A, class B>
  static constexpr bool convertible() {
    return std::is_convertible<A, B>();
  }
};

namespace detail {
namespace concept {

template <
    class Concept, class... Args,
    typename T = decltype(std::declval<Concept>().template require<Args...>(
        std::declval<Args>()...)),
    typename std::enable_if<std::is_same<T, std::true_type>::value, int>::type =
        0>
std::true_type models_(Args&&... args);

template <class Concept, class... Args>
std::false_type models_(...);

}  // end namespace concept
}  // end namespace detail

template <class Concept, class... Args>
constexpr bool models() {
  using Result = decltype(
      detail::concept::models_<Concept, Args...>(std::declval<Args>()...));
  return Result{};
}

struct Scalar : Concept {
  template <class T>
  auto require(T&& x)
      -> list<std::is_pod<T>::value, same<T, decltype(-x)>(),
              same<T, decltype(x + x)>(), same<T, decltype(x - x)>(),
              same<T, decltype(x* x)>(), same<T, decltype(x / x)>()>;
};

template <class T>
constexpr bool scalar() {
  return models<Scalar, T>();
}

/*************   Block A   ***********/
struct MatrixEvaluator : Concept {
  template <class T>
  auto require(T&& evaluator)
      -> list<scalar<std::decay_t<decltype(evaluator(0, 0, 0, 0))>>()>;
};
/************* End Block A ***********/

struct VectorEvaluator : Concept {
  template <class T>
  auto require(T&& evaluator)
      -> list<scalar<std::decay_t<decltype(evaluator(0))>>()>;
};

template <class T>
constexpr bool vector_evaluator() {
  return models<VectorEvaluator, T>();
}

int main() {
  auto f = [](int x) -> double { return x * x; };
  static_assert(vector_evaluator<decltype(f)>(), "");
  return 0;
}

 

 

0 Kudos
2 Replies
Judith_W_Intel
Employee
289 Views

It looks like you must be using the -std=c++14 option in order for std::decay_t to be found.

Anyway this does look a bug and I have entered it into our bug tracking database as DPD200369406.

The problem in our compiler seems to be the reuse of the "scalar" constexpr routine inside the unused member function inside MatrixEvaluator.

So one possible workaround is to create a copy of scalar for use in MatrixEvaluator, i.e. I've created a duplicate routine called

matrixscalar) -- the diff would be:

sptel15-458> diff -c orig.cpp workaround.cpp
*** orig.cpp    2015-04-21 16:27:02.821708000 -0400
--- workaround.cpp      2015-04-21 16:39:57.327377000 -0400
***************
*** 72,82 ****
    return models<Scalar, T>();
  }

  /*************   Block A   ***********/
  struct MatrixEvaluator : Concept {
    template <class T>
    auto require(T&& evaluator)
!       -> list<scalar<std::decay_t<decltype(evaluator(0, 0, 0, 0))>>()>;
  };
  /************* End Block A ***********/

--- 72,87 ----
    return models<Scalar, T>();
  }

+ template <class T>
+ constexpr bool matrixscalar() {
+   return models<Scalar, T>();
+ }
+
  /*************   Block A   ***********/
  struct MatrixEvaluator : Concept {
    template <class T>
    auto require(T&& evaluator)
!       -> list<matrixscalar<std::decay_t<decltype(evaluator(0, 0, 0, 0))>>()>;
  };
  /************* End Block A ***********/

sptel15-459>

Sorry for the inconvenience and thanks for reporting it to us.

Judy

0 Kudos
rnickb
Beginner
289 Views

Thanks for the response. I found another workaround replacing the decltype expression with std::result_of_t.

0 Kudos
Reply