我正在编写一段通用的 (C++11) 代码,它应该与 boost::multi_array
、Eigen::Matrix
一起工作,并且可能其他类型的 n 维数组。在几个点上,我需要访问给定数组类型的元素类型。 boost 数组包含一个名为 Element
的 typedef,而 Eigen 数组包含一个名为 Scalar
的 typedef。
我想要的是一个返回给定数组类型的元素类型的类型特征。不幸的是,我不能只为所有可能的数组类型模板专门化特征类,因为 Eigen 使用表达式模板,因此,有无限多种类型的 Eigen 矩阵。因此,我将 SFINAE 与 enable_if 一起使用来实现我的特征。 enable_if 应该选择的标准是,一个类型是否有一个名为 Element
的 typedef,或一个名为 Scalar
的 typedef。
为此,我实现了类型特征 has_element
和 has_scalar
,它们确定相应的 typedef 是否存在。我的实现灵感来自 this blog post关于类型要求。
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 {};
想法是,如果没有提供 typedef,编译器将选择 false_type
版本,并将选择更专业的 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 版本是 here并且工作正常。 gcc 版本是 here编译失败。
我的问题:我的代码是否正确,这是 GCC 4.8.1 的问题;还是我做错了什么而 Clang 在编译时过于慷慨?在任何情况下,我如何更改我的代码以使 GCC 4.8.1 能够编译它?
最佳答案
看起来是 yet another manifestation的 CWG issue 1558 .该标准不清楚别名模板中未使用的模板参数是否会导致替换失败。 Clang 将其视为替换失败; GCC 会简单地忽略未使用的参数。
使用
template<typename... Ts>
struct make_void { typedef void type;};
template<typename... Ts>
using ToVoid = typename make_void<Ts...>::type;
关于c++ - 使用 enable_if 选择特征 - 适用于 clang,但不适用于 gcc,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26143259/