Selecting traits with enable_if - works with clang, but not with gcc

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 ?

+4
1

CWG- 1558. , . ; GCC .

template<typename... Ts>
struct make_void { typedef void type;};

template<typename... Ts>
using ToVoid = typename make_void<Ts...>::type;

, .

+10

All Articles