简体   繁体   English

使用模板 C++ 检查类型

[英]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说:如果( MMatrix ),将应用的返回类型声明为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(...)什么都declvaldecltype在此代码做什么,它是如何可能的检查可以返回一个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) 如果MMatrix<T, N> (或可转换为Matrix<T, N> ),对于某些T和某些NN >= 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) 如果MMatrixRef<T, N> (或可转换为MatrixRef<T, N> ),对于某些T和某些NN >= 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_failuresubstitution_succeded

But, maybe, the code is written this way for other needs.但是,也许,代码是为了其他需求而编写的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM