I am working on a common piece of code (C ++ 11) that should work with boost::multi_array, Eigen::Matrixand possibly with other types of n-dimensional arrays. At several points, I need access to the element type of the given array type. Massive arrays contain a typedef called Element, while Eigen arrays contain a typedef called Scalar.
What I want is an attribute type that returns the element type of the given array type. Unfortunately, I cannot just specialize a feature class for all possible array types because Eigen uses expression patterns, and therefore there are infinitely many types of native matrices. Therefore, I use SFINAE with enable_if to implement my properties. The criterion that enable_if should choose is whether the type has a typedef called Element, or one called Scalar.
To do this, I applied type traits has_elementand has_scalar, which determine whether the corresponding typedef exists. My implementation is inspired by this blog post about the requirements for the type.
template <class T>
using ToVoid = void;
template <class T, class Enable = void>
struct has_scalar : public std::false_type {};
template <class T>
struct has_scalar<T, ToVoid<typename T::Scalar>> : public std::true_type {};
template <class T, class Enable = void>
struct has_element : public std::false_type {};
template <class T>
struct has_element<T, ToVoid<typename T::Element>> : public std::true_type {};
, false_type, typedef , true_type, typedef.
:
template <class Condition, class T = void>
using EnableIf = typename std::enable_if<Condition::value, T>::type;
template <class T, class Enable = void>
struct scalar_of;
template <class T>
struct scalar_of<T, EnableIf<has_element<T>>> {
using type = typename T::Element;
};
template <class T>
struct scalar_of<T, EnableIf<has_scalar<T>>> {
using type = typename T::Scalar;
};
template <class T>
using ScalarOf = typename scalar_of<T>::type;
:
struct BoostArray {
using Element = double;
};
struct EigenArray {
using Scalar = float;
};
int main() {
using std::is_same;
assert((is_same<double, ScalarOf<BoostArray>>::value));
assert((is_same<float, ScalarOf<EigenArray>>::value));
}
, , Clang 3.4. GCC 4.8.1 :
test.cpp: In substitution of ‘template<class T> using ScalarOf = typename scalar_of<T>::type [with T = BoostArray]’:
test.cpp:51:5: required from here
test.cpp:37:45: error: ambiguous class template instantiation for ‘struct scalar_of<BoostArray, void>’
using ScalarOf = typename scalar_of<T>::type;
^
test.cpp:27:8: error: candidates are: struct scalar_of<T, typename std::enable_if<has_element<T, void>::value, void>::type>
struct scalar_of<T, EnableIf<has_element<T>>> {
^
test.cpp:32:8: error: struct scalar_of<T, typename std::enable_if<has_scalar<T, void>::value, void>::type>
struct scalar_of<T, EnableIf<has_scalar<T>>> {
clang . gcc .
: , GCC 4.8.1; - , ? , , GCC 4.8.1 ?