[英]Checking type with template C++
I'm studying the implementation of the Matrix
class (explained in Stroustrup's book TC++PL 4th ed.), but I can't really understand some passages.我正在研究Matrix
类的实现(在 Stroustrup 的书 TC++PL 第 4 版中有解释),但我无法真正理解一些段落。
I found this code:我找到了这个代码:
file traits.h -> https://github.com/statslabs/matrix/blob/master/include/slab/matrix/traits.h文件 traits.h -> https://github.com/statslabs/matrix/blob/master/include/slab/matrix/traits.h
file matrix.h -> https://github.com/statslabs/matrix/blob/master/include/slab/matrix/matrix.h文件 matrix.h -> https://github.com/statslabs/matrix/blob/master/include/slab/matrix/matrix.h
In matrix.h there is a function (as many other) with Enable_if
:在matrix.h有一个函数(如许多其他)与Enable_if
:
template<typename T, std::size_t N>
template<typename M, typename F>
Enable_if<Matrix_type<M>(), Matrix<T, N> &> Matrix<T, N>::apply(const M &m, F f) {
/// Some code...
}
and I think Enable_if
says: If ( M
is a Matrix
), declare the apply's return type as Matrix<T, N>&
.我认为Enable_if
说:如果( M
是Matrix
),将应用的返回类型声明为Matrix<T, N>&
。
Then, I want to know how does Matrix_type<M>()
works, so I go to traits.h
, and I read:然后,我想知道Matrix_type<M>()
是如何工作的,所以我转到了traits.h
,并阅读了:
struct substitution_failure {};
template <typename T>
struct substitution_succeeded : std::true_type {};
template <>
struct substitution_succeeded<substitution_failure> : std::false_type {};
template <typename M>
struct get_matrix_type_result {
template <typename T, size_t N, typename = Enable_if<(N >= 1)>>
static bool check(const Matrix<T, N> &m);
template <typename T, size_t N, typename = Enable_if<(N >= 1)>>
static bool check(const MatrixRef<T, N> &m);
static substitution_failure check(...);
using type = decltype(check(std::declval<M>()));
};
template <typename T>
struct has_matrix_type
: substitution_succeeded<typename get_matrix_type_result<T>::type> {};
template <typename M>
constexpr bool Has_matrix_type() {
return has_matrix_type<M>::value;
}
template <typename M>
using Matrix_type_result = typename get_matrix_type_result<M>::type;
template <typename M>
constexpr bool Matrix_type() {
return Has_matrix_type<M>();
}
The first 3 structs describe success and failure cases, the template<>
is the specialization of substitution_succeeded
that says: if the type of substitution_succeeded
is substitution_failure
, "return" false else "return" true.前 3 个结构描述成功和失败的情况, template<>
是substitution_succeeded
,它表示:如果substitution_succeeded
的类型是substitution_failure
,则“return”false 否则“return”true。 I hope that what I'm saying is correct.我希望我说的是正确的。
Now, get_matrix_type_result
is completely obscure.现在, get_matrix_type_result
完全模糊。 I can't understand why it use a variadic function ( check(...)
), what are declval
and decltype
doing in this code and how it is possible that check can return a bool or a substitution_failure
.我不明白为什么它使用可变参数函数( check(...)
什么都declval
和decltype
在此代码做什么,它是如何可能的检查可以返回一个bool或substitution_failure
。 Why not just bool
?为什么不只是bool
?
Thanks.谢谢。
Now, get_matrix_type_result is completely obscure.现在, get_matrix_type_result 完全模糊。 I can't understand why it use a variadic function (check(...)), what are declval and decltype doing in this code and how it is possible that check can return a bool or a "substitution_failure".我不明白为什么它使用可变参数函数 (check(...)),这段代码中 declval 和 decltype 做了什么,以及 check 怎么可能返回 bool 或“substitution_failure”。 Why not just bool?为什么不只是布尔?
An important point is that Enable_if
( std::enable_if
starting from C++11) is designed to enable or not enable something (a template function, a template class specialization, a template method, a template variable specialization).一个重要的点是Enable_if
( std::enable_if
从 C++11 开始) 旨在启用或不启用某些东西(模板函数、模板类特化、模板方法、模板变量特化)。
On the ground is a C++ principle named SFINAE (Substitution Failure Is Not An Error) that say that, in some places, if a substitution do not take place, it's only a soft error, non an hard error, and the compilation can continue.在地面上是一个名为 SFINAE(替换失败不是错误)的 C++ 原则,它说,在某些地方,如果没有发生替换,它只是一个软错误,而不是一个硬错误,编译可以继续。
In your case, you have that type
is defined as follows在您的情况下,您的type
定义如下
using type = decltype(check(std::declval<M>()));
where decltype()
"return" the type of the argument;其中decltype()
“返回”参数的类型; in this case, the type returned from a call to check()
with an hypothetical object of type M
(the template parameter of the class).在这种情况下,调用check()
返回的类型是一个假设的类型为M
对象(类的模板参数)。
You could write你可以写
using type = decltype(check(M{}));
to pass an object of type M
.传递M
类型的对象。 But this works only with types that are default constructible.但这仅适用于默认可构造的类型。 The question is: how to use, in a decltype()
argument (that has the exclusive function to deduce types, not execute instructions) an object of a generic type if we don't know how construct an object of that type?问题是:如果我们不知道如何构造该类型的对象,如何在decltype()
参数(具有推导类型的独占功能,而不是执行指令)中使用泛型类型的对象?
The solution is a function only declared (not defined) as follows解决方法是只声明(未定义)的函数如下
template<class T>
typename std::add_rvalue_reference<T>::type declval() noexcept;
This is a trick to have an object of type T
(or better: T &
) also when do you don't know how to construct it.这是拥有T
类型对象(或更好: T &
)的技巧,而且您何时不知道如何构造它。
Returning to check
, you have three version of it (only declared: are used inside a decltype()
; we are only interested in the returned type so there is no need to execute them, so there is no need to define them):回到check
,你有它的三个版本(只声明:在decltype()
;我们只对返回的类型感兴趣,所以不需要执行它们,所以不需要定义它们):
1) the first one accept a Matrix<T, N>
but only ( Enable_if
) if N >= 1
1) 第一个接受Matrix<T, N>
但只有( Enable_if
) 如果N >= 1
template <typename T, size_t N, typename = Enable_if<(N >= 1)>>
static bool check(const Matrix<T, N> &m);
If you call check()
with a Matrix<T, 0>
, the Enable_if
return nothing so you have a substitution failure (defining the default for a template parameter) so this version of check()
isn't enabled如果您使用Matrix<T, 0>
调用check()
,则Enable_if
返回任何内容,因此您会出现替换失败(定义模板参数的默认值),因此未启用此版本的check()
2) the second one accept a MatrixRef<T, N>
but only ( Enable_if
) if N >= 1
2) 第二个接受MatrixRef<T, N>
但只有( Enable_if
) 如果N >= 1
template <typename T, size_t N, typename = Enable_if<(N >= 1)>>
static bool check(const MatrixRef<T, N> &m);
Again: if you call check()
with a MatrixRef<T, 0>
, the Enable_if
return nothing so you have a substitution failure (defining the default for a template parameter) so this version of check()
isn't enabled还是那句话:如果你调用check()
与MatrixRef<T, 0>
该Enable_if
任何回报,所以你必须(定义为模板参数的默认)替换故障所以这个版本的check()
未启用
3) the third one accept everything and is ever enabled 3)第三个接受一切并且永远启用
static substitution_failure check(...);
Conclusion:结论:
1) if M
is a Matrix<T, N>
(or an object convertible to a Matrix<T, N>
), for some T
and some N
with N >= 1
, the compiler can choose between version (1) and version (3) of check()
and choose version (1) because more specialized, that return bool
, so type
become bool
1) 如果M
是Matrix<T, N>
(或可转换为Matrix<T, N>
),对于某些T
和某些N
且N >= 1
,编译器可以在版本 (1) 和版本之间进行选择(3) 的check()
并选择版本 (1) 因为更专业,返回bool
,所以type
变成bool
2) if M
is a MatrixRef<T, N>
(or an object convertible to a MatrixRef<T, N>
), for some T
and some N
with N >= 1
, the compiler can choose between version (2) and version (3) of check()
and choose version (2) because more specialized, that return bool
, so type
become bool
2) 如果M
是MatrixRef<T, N>
(或可转换为MatrixRef<T, N>
),对于某些T
和某些N
且N >= 1
,编译器可以在版本 (2) 和版本之间进行选择(3) 的check()
并选择版本 (2) 因为更专业,返回bool
,所以type
变成bool
3) if M
isn't convertible to a Matrix<T, N>
or a MatrixRef<T, N>
, with N >= 1
, the compiler can choose only version (3), that return a substitution_failure
, so type
become substitution_failure
. 3)如果M
是无法转换为一个Matrix<T, N>
或MatrixRef<T, N>
其中N >= 1
,编译器可以选择仅版本(3),即返回一个substitution_failure
,所以type
成为substitution_failure
.
Off Topic: the code you show us seems to me a little overcomplicated.题外话:您向我们展示的代码在我看来有点过于复杂。
By example, if you rewrite get_matrix_type_result
as follows举个例子,如果你重写get_matrix_type_result
如下
template <typename M>
struct get_matrix_type_result {
template <typename T, size_t N, typename = Enable_if<(N >= 1)>>
static std::true_type check(const Matrix<T, N> &m);
template <typename T, size_t N, typename = Enable_if<(N >= 1)>>
static std::true_type check(const MatrixRef<T, N> &m);
static std::false_type check(...);
using type = decltype(check(std::declval<M>()));
};
you have that type
is the type that you needs in has_matrix_type
that can be defined as follows你有那个type
是你在has_matrix_type
中需要的类型,可以定义如下
template <typename T>
struct has_matrix_type
: public get_matrix_type_result<T>::type
{ };
avoiding at all substitution_failure
and substitution_succeded
.完全避免substitution_failure
和substitution_succeded
。
But, maybe, the code is written this way for other needs.但是,也许,代码是为了其他需求而编写的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.