C++ std::optional完全解读

news/2025/3/23 17:35:08/

文章目录

    • 引言
    • std::optional\<T\>基本用法介绍
      • 成员函数
        • 构造函数
        • 析构函数
        • operator=
      • 观察器
        • 访问所含值
        • 检查对象是否含值
        • 返回所含值
        • 在所含值可用时返回它,否则返回默认值
      • 单子操作
        • and_then
        • transform
        • or_else
      • 修改器
        • swap
        • reset
        • emplace
      • 非成员函数
        • 比较 optional 对象
        • make_optional
        • std::swap(std::optional)
    • 何时使用
    • 使用示例
        • 函数返回 std::optional
        • 延时初始化
        • 作为可选参数
    • 总结

引言

在编写可选择接受或返回对象的函数的时候,通常的做法是选择一个单独的布尔值来确保函数入参或者返回对象的可用性:

//使用is_valid来指示入参value是否有效
void maybe_take_an_int(int value = -1bool is_valid = false) //使用bool代表返回的int是否有效
bool maybe_return_an_int(int &value) //or
std::pair<int, bool> maybe_return_an_int()

上面的例子是可行的,但是本来我们只是为了传递或者得到一个value,但为了确保value的可用性需要增加一个布尔作为可用的指示,当调用者忘记bool简单调用maybe_take_an_int(1)时,该函数会默认失败,同样的在读取bool maybe_return_an_int(int &value)中的value值的时候,若忽略返回bool的值的时候,可能会导致读取的value是无效的。虽然在std::pair<int, bool> maybe_return_an_int()中使用了pair看似将两者进行了绑定,但是还是不能避免使用者忘记检查bool,导致使用了不可用的value

C++17中提供了std::optional<T>来解决这类问题,我们可以将optional<T>看作是T类型和bool的一个打包。其与std::pair<T, bool>相比其显示的表达意图,更加可读,而且可以良好地处理构造开销高昂的对象。使用std::optional<T>,上面的问题可变为

void maybe_take_an_int(optional<int> potential_value = nullopt); optional<int> maybe_return_an_int();

optional<T> 直接解决传递或存储当前可能或可能不是对象时出现的问题。optional<T>提供接口来确定它是否包含 并 T 查询存储的值。我们可以使用实际T值初始化 ,optional或者默认初始化它(或初始化为 std::nullopt )以将其置于“空”状态。

std::nullopt_t 是空类类型,用于指示optional类型拥有未初始化状态。

std::optional<T>基本用法介绍

std::optional<T>是一个管理一个可选的容纳值(既可以存在,也可以不存在的值)的类模板。任何一个std::optional<T>实例在给定的时间点要么含值,要么不含值。其在 <optional> 定义,函数原型如下:

template< class T >
class optional; //C++17 起
  • T:要为管理状态的值的类型,该校类型需要满足可析构克的要求。(特别是不允许数组类型)

成员函数

构造函数
//构造不含 值的对象。
constexpr optional() noexcept; //C++17 起
constexpr optional( std::nullopt_t ) noexcept; //C++17 起/*复制构造函数:如果 other 包含值,那么初始化所含值,
如同以表达式 *other 直接初始化(但不是直接列表初始化)T 类型对象。
如果 other 不含值,那么构造一个不含 值的对象。*/
constexpr optional( const optional& other ); //C++17 起/*移动构造函数:如果 other 含值,那么初始化所含值,
如同以表达式 std::move(*other) 直接初始化(但不是直接列表初始化) T 类型对象,
且不 令 other 为空:被移动的 std::optional 仍然包含 值,但该值自身是被移动的。*/
constexpr optional( optional&& other ) noexcept(); //C++17 起	/*转换复制构造函数:如果 other 不含值,那么构造不含值的 optional 对象。
否则,构造含值的 optional 对象,如同以表达式 *other 直接初始化
(但不是直接列表初始化) T 类型对象一般初始化。*/
template < class U >
optional( const optional<U>& other ); //C++17 起, C++20 前 (条件性 explicit)
template < class U >
constexpr optional( const optional<U>& other ); //C++20 起 (条件性 explicit)/*转换移动构造函数:如果 other 不含值,那么构造不含值的 optional 对象。
否则,构造含值的 optional 对象,如同以表达式 std::move(*other) 直接初始化
(但不是直接列表初始化) T 类型对象一般初始化。*/
template < class U >
optional( optional<U>&& other ); //C++17 起, C++20 前 (条件性 explicit)
template < class U >
constexpr optional( optional<U>&& other ); //C++20 起 (条件性 explicit)/*构造一个包含的对象,如同从参数 std::forward<Args>(args)... 
直接初始化(但不是直接列表初始化) T 类型对象一般初始化。r*/
template< class... Args >
constexpr explicit optional( std::in_place_t, Args&&... args ); //C++17 起/*构造一个包含的对象,如同从参数 ilist, std::forward<Args>(args)... 
直接初始化(但不是直接列表初始化) T 类型对象一般初始化。*/
template< class U, class... Args >
constexpr explicit optional( std::in_place_t,std::initializer_list<U> ilist,Args&&... args ); //C++17 起/*构造一个包含的对象,如同从参数 std::forward<U>(value) 
直接初始化(但不是直接列表初始化) T 类型对象一般初始化。*/                             
template < class U = T >
constexpr optional( U&& value ); //C++17 起 (条件性 explicit)

示例:

#include <iostream>
#include <optional>
#include <string>int main()
{std::optional<int> o1, // 空o2 = 1, // 从右值初始化o3 = o2; // 复制构造函数// 调用 std::string( initializer_list<CharT> ) 构造函数std::optional<std::string> o4(std::in_place, {'a', 'b', 'c'});// 调用 std::string( size_type count, CharT ch ) 构造函数std::optional<std::string> o5(std::in_place, 3, 'A');// 从 std::string 移动构造,用推导指引拾取类型std::optional o6(std::string{"deduction"});std::cout << *o2 << ' ' << *o3 << ' ' << *o4 << ' ' << *o5  << ' ' << *o6 << '\n';
}

std::in_place是消除歧义的标签,其传递给ystd::optional的构造函数,用来指示原位构造对象。

输出:

1 1 abc AAA deduction
析构函数
~optional(); //C++17 起, C++20 前
constexpr ~optional(); //C++20 起
operator=
//若 *this 在调用前含值,则通过调用其析构函数销毁所含值,如同用 value().T::~T() 。此调用后 *this 不含值。
optional& operator=( std::nullopt_t ) noexcept; //C++17 起, C++20 前
constexpr optional& operator=( std::nullopt_t ) noexcept; //C++20 起//赋值 other 的状态
constexpr optional& operator=( const optional& other ); //C++17 起//赋值 other 的状态
constexpr optional& operator=( optional&& other ) noexcept(); //C++17 起/*完美转发赋值:取决于 *this 在调用前是否含值,从 std::forward<U>(value) 直接初始化,
或从 std::forward<U>(value) 赋值被含有值。*/
template< class U = T >
optional& operator=( U&& value ); //C++17 起, C++20 前
template< class U = T >
constexpr optional& operator=( U&& value ); //C++20 起//赋值 other 的状态
template< class U >
optional& operator=( const optional<U>& other ); //C++17 起, C++20 前
template< class U >
constexpr optional& operator=( const optional<U>& other ); //C++20 起//赋值 other 的状态
template< class U >
optional& operator=( optional<U>&& other ); //C++17 起, C++20 前
template< class U >
constexpr optional& operator=( optional<U>&& other ); //C++20 起

示例:

#include <optional>
#include <iostream>
int main()
{std::optional<const char*> s1 = "abc", s2; // 构造函数s2 = s1; // 赋值s1 = "def"; // 衰变赋值( U = char[4], T = const char* )std::cout << *s2 << ' ' << *s1 << '\n';
}

输出:

abc def

观察器

访问所含值

optionalstd::optional<T>::operator->, std::optional<T>::operator*函数主要的作用就是用来访问所含值,其原型如下:

//返回指向所含值的指针。
constexpr const T* operator->() const noexcept; //C++17 起
constexpr T* operator->() noexcept; //C++17 起//返回到所含值的引用。
constexpr const T& operator*() const& noexcept; //C++17 起
constexpr T& operator*() & noexcept; //C++17 起
constexpr const T&& operator*() const&& noexcept; //C++17 起
constexpr T&& operator*() && noexcept; //C++17 起

注:若*this不含值则行为未定义。

示例:

#include <optional>
#include <iostream>
#include <string>int main()
{using namespace std::string_literals;std::optional<int> opt1 = 1;std::cout<< "opt1: "  << *opt1 << '\n';*opt1 = 2;std::cout<< "opt1: "  << *opt1 << '\n';std::optional<std::string> opt2 = "abc"s;std::cout<< "opt2: " << *opt2 << " size: " << opt2->size() << '\n';// 你能通过在到 optional 的右值上调用 operator* “取”其所含值auto taken = *std::move(opt2);std::cout << "taken: " << taken << " opt2: " << *opt2 << "size: " << opt2->size()  << '\n';
}

输出:

opt1: 1
opt1: 2
opt2: abc size: 3
taken: abc opt2: size: 0
检查对象是否含值

std::optional<T>::operator bool, std::optional<T>::has_value函数用来检查 *this 是否含值。若 *this 含值则为true,若*this不含值则 false 。 其函数原型为:

constexpr explicit operator bool() const noexcept; //C++17 起
constexpr bool has_value() const noexcept; //C++17 起
返回所含值

std::optional<T>::value函数返回所含值,若 *this 含值,则返回到所含值引用。否则,抛出 std::bad_optional_access 异常。 其函数原型如下:

constexpr T& value() &;
constexpr const T& value() const&; //C++17 起
constexpr T&& value() &&;
constexpr const T&& value() const&&; //C++17 起

:解引用运算符 operator*() 不检查此optional是否含值,它可能比value()更有效率。

示例:

#include <optional>
#include <iostream>
int main()
{std::optional<int> opt = {};try {int n = opt.value();} catch(const std::exception& e) {std::cout << e.what() << '\n';}
}

输出:

bad optional access
在所含值可用时返回它,否则返回默认值

std::optional<T>::value_or函数在*this 拥有值则返回其所含的值,否则返回 default_value 。其函数原型如下:

template< class U >
constexpr T value_or( U&& default_value ) const&; //C++17 起
template< class U >
constexpr T value_or( U&& default_value ) &&; //C++17 起

示例:

#include <optional>
#include <iostream>
#include <cstdlib>std::optional<const char*> maybe_getenv(const char* n)
{if(const char* x = std::getenv(n))return x;elsereturn {};
}
int main()
{std::cout << maybe_getenv("MYPWD").value_or("(none)") << '\n';
}

输出:

(none)

单子操作

and_then

std::optional<T>::and_then在所含值存在时返回对其应用给定的函数的结果,否则返回空的optional,其函数原型为:

template< class F >
constexpr auto and_then( F&& f ) &; //C++23 起template< class F >
constexpr auto and_then( F&& f ) const&; //C++23 起template< class F >
constexpr auto and_then( F&& f ) &&; //C++23 起template< class F >
constexpr auto and_then( F&& f ) const&&; //C++23 起

若所含值存在则返回在其上调用 f 的结果。否则,返回返回类型的空值。
示例:

#include <iostream>
#include <optional>
std::optional<int> add5(int x)
{return x + 5;
}
std::optional<int> multiply2(int x)
{return x * 2;
}
int main()
{std::optional<int> x = 10;auto y = x.and_then(add5).and_then(multiply2);if (y){std::cout << "Result: " << *y << std::endl; }else{std::cout << "Result is empty" << std::endl;}std::optional<int> z;auto w = z.and_then(add5).and_then(multiply2);if (w){std::cout << "Result: " << *w << std::endl;}else{std::cout << "Result is empty" << std::endl; // Output: Result is empty}return 0;
}

输出:

Result: 30
Result is empty
transform

std::optional<T>::transform函数在所含值存在时返回含有变换后的所含值的 optional,否则返回空的 optional,其函数原型如下:

template< class F >
constexpr auto transform( F&& f ) &; //C++23 起template< class F >
constexpr auto transform( F&& f ) const&; //C++23 起template< class F >
constexpr auto transform( F&& f ) &&; //C++23 起template< class F >
constexpr auto transform( F&& f ) const&&; //C++23 起

*this含值则返回含有f在所含值上调用结果的 std::optional 。否则返回这种类型的空 std::optional

示例:

#include <iostream>
#include <optional>struct A { /* ... */ };
struct B { /* ... */ };
struct C { /* ... */ };
struct D { /* ... */ };auto A_to_B(A) -> B { /* ... */ std::cout << "A => B \n"; return {}; }
auto B_to_C(B) -> C { /* ... */ std::cout << "B => C \n"; return {}; }
auto C_to_D(C) -> D { /* ... */ std::cout << "C => D \n"; return {}; }void try_transform_A_to_D(std::optional<A> o_A)
{std::cout << (o_A ? "o_A has a value\n" : "o_A is empty\n");std::optional<D> o_D = o_A.transform(A_to_B).transform(B_to_C).transform(C_to_D);std::cout << (o_D ? "o_D has a value\n\n" : "o_D is empty\n\n");
};int main()
{try_transform_A_to_D( A{} );try_transform_A_to_D( {} );
}

输出:

o_A has a value
A => B
B => C
C => D
o_D has a valueo_A is empty
o_D is empty
or_else

std::optional<T>::or_else函数在 optional 含值时返回自身,否则返回给定函数的结果。其函数原型如下:

template< class F >
constexpr optional or_else( F&& f ) const&; //C++23 起
template< class F >
constexpr optional or_else( F&& f ) &&; //C++23 起

*this 含值则返回它。否则返回 f 的结果。

修改器

swap
void swap( optional& other ) noexcept(/* see below */); //C++17 起, C++20 前
constexpr void swap( optional& other ) noexcept(/* see below */); //C++20 起

std::optional<T>::swap用来与 other 交换内容。

示例:

#include <iostream>
#include <string>
#include <optional>int main()
{std::optional<std::string> opt1("First example text");std::optional<std::string> opt2("2nd text");enum Swap { Before, After };auto print_opts = [&](Swap e) {std::cout << (e == Before ? "Before swap:\n" : "After swap:\n");std::cout << "opt1 contains '" << opt1.value_or("") << "'\n";std::cout << "opt2 contains '" << opt2.value_or("") << "'\n";std::cout << (e == Before ? "---SWAP---\n": "\n");};print_opts(Before);opt1.swap(opt2);print_opts(After);// 在仅一者含值时交换opt1 = "Lorem ipsum dolor sit amet, consectetur tincidunt.";opt2.reset();print_opts(Before);opt1.swap(opt2);print_opts(After);
}

输出:

Before swap:
opt1 contains 'First example text'
opt2 contains '2nd text'
---SWAP---
After swap:
opt1 contains '2nd text'
opt2 contains 'First example text'Before swap:
opt1 contains 'Lorem ipsum dolor sit amet, consectetur tincidunt.'
opt2 contains ''
---SWAP---
After swap:
opt1 contains ''
opt2 contains 'Lorem ipsum dolor sit amet, consectetur tincidunt.'
reset
void reset() noexcept; //C++17 起, C++20 前
constexpr void reset() noexcept; //C++20 起

std::optional<T>::reset用来销毁任何所含值,若 *this 含值,则如同用value().T::~T()销毁此值。否则无效果。
*this 在此调用后不含值。

示例:

#include <optional>
#include <iostream>struct A {std::string s;A(std::string str) : s(std::move(str))  { std::cout << " constructed\n"; }~A() { std::cout << " destructed\n"; }A(const A& o) : s(o.s) { std::cout << " copy constructed\n"; }A(A&& o) : s(std::move(o.s)) { std::cout << " move constructed\n"; }A& operator=(const A& other) {s = other.s;std::cout << " copy assigned\n";return *this;}A& operator=(A&& other) {s = std::move(other.s);std::cout << " move assigned\n";return *this;}
};int main()
{std::cout << "Create empty optional:\n";std::optional<A> opt;std::cout << "Construct and assign value:\n";opt = A("Lorem ipsum dolor sit amet, consectetur adipiscing elit nec.");std::cout << "Reset optional:\n";opt.reset();std::cout << "End example\n";
}

输出:

Create empty optional:
Construct and assign value:constructedmove constructeddestructed
Reset optional:destructed
End example
emplace

std::optional<T>::emplace用来原位构造所含值 ,其函数原型如下:

//以 std::forward<Args>(args)... 为参数直接初始化(但不是直接列表初始化)所含值。
template< class... Args >
T& emplace( Args&&... args ); //C++17 起, C++20 前
template< class... Args >
constexpr T& emplace( Args&&... args ); //C++20 起//以 ilist, std::forward<Args>(args)... 为参数直接初始化(但不是直接列表初始化)所含值。
template< class U, class... Args >
T& emplace( std::initializer_list<U> ilist, Args&&... args ); //C++17 起, C++20 前
template< class U, class... Args >
constexpr T& emplace( std::initializer_list<U> ilist, Args&&... args ); //C++20 起

*this已在此调用前含值,则调用其析构函数销毁所含值。

示例:

#include <optional>
#include <iostream>struct A {std::string s;A(std::string str) : s(std::move(str))  { std::cout << " constructed\n"; }~A() { std::cout << " destructed\n"; }A(const A& o) : s(o.s) { std::cout << " copy constructed\n"; }A(A&& o) : s(std::move(o.s)) { std::cout << " move constructed\n"; }A& operator=(const A& other) {s = other.s;std::cout << " copy assigned\n";return *this;}A& operator=(A&& other) {s = std::move(other.s);std::cout << " move assigned\n";return *this;}
};int main()
{std::optional<A> opt;std::cout << "Assign:\n";opt = A("Lorem ipsum dolor sit amet, consectetur adipiscing elit nec.");std::cout << "Emplace:\n";// 由于 opt 含值,这亦将销毁该值opt.emplace("Lorem ipsum dolor sit amet, consectetur efficitur. ");std::cout << "End example\n";
}

输出:

Assign:constructedmove constructeddestructed
Emplace:destructedconstructed
End exampledestructed

非成员函数

比较 optional 对象

operator==, !=, <, <=, >, >=, <=>(std::optional)函数用来比较optional对象。

示例:

#include <optional>
#include <iostream>int main()
{std::optional<int> oEmpty;std::optional<int> oTwo(2);std::optional<int> oTen(10);std::cout << std::boolalpha;std::cout << (oTen > oTwo) << "\n";std::cout << (oTen < oTwo) << "\n";std::cout << (oEmpty < oTwo) << "\n";std::cout << (oEmpty == std::nullopt) << "\n";std::cout << (oTen == 10) << "\n";
}

输出:

true  
false 
true 
true  
true  
make_optional

std::make_optional函数用来创建一个optional对象 。其函数原型如下:

//从value 创建 optional 对象。
template< class T >
constexpr std::optional<std::decay_t<T>> make_optional( T&& value ); //C++17 起//从 args... 创建原位构造的 optional 对象。
template< class T, class... Args >
constexpr std::optional<T> make_optional( Args&&... args ); //C++17 起//从 il 和 args... 创建原位构造的 optional 对象。
template< class T, class U, class... Args >
constexpr std::optional<T> make_optional( std::initializer_list<U> il, Args&&... args ); //C++17 起

示例:

#include <optional>
#include <iostream>
#include <iomanip>
#include <vector>
#include <string>int main()
{auto op1 = std::make_optional<std::vector<char>>({'a','b','c'});std::cout << "op1: ";for (char c: op1.value()){std::cout << c << ",";}auto op2 = std::make_optional<std::vector<int>>(5, 2);std::cout << "\nop2: ";for (int i: *op2){std::cout << i << ",";}std::string str{"hello world"};auto op3 = std::make_optional<std::string>(std::move(str));std::cout << "\nop3: " << quoted(op3.value_or("empty value")) << '\n';std::cout << "str: " << std::quoted(str) << '\n';
}

输出:

op1: a,b,c,
op2: 2,2,2,2,2,
op3: "hello world"
str:
std::swap(std::optional)

std::swap(std::optional)是特化 std::swap 算法 ,其函数原型如下:

template< class T >void swap( std::optional<T>& lhs,std::optional<T>& rhs ) noexcept(/* see below */); //C++17 起, C++20 前
template< class T >constexpr void swap( std::optional<T>& lhs,std::optional<T>& rhs ) noexcept(); //C++20 起

std::optional重载 std::swap 算法。交换lhsrhs 的状态。等效地调用 lhs.swap(rhs)
示例:


#include <iostream>
#include <optional>
#include <string>int main()
{std::optional<std::string> a{"██████"}, b{"▒▒▒▒▒▒"}; auto print = [&](auto const& s) {std::cout << s << "\t"<< "a = " << a.value_or("(null)") << "  "<< "b = " << b.value_or("(null)") << '\n';};print("Initially:");std::swap(a, b);print("swap(a, b):");a.reset();print("\n""a.reset():");std::swap(a, b);print("swap(a, b):");
}

输出:

Initially:	a = ██████  b = ▒▒▒▒▒▒
swap(a, b):	a = ▒▒▒▒▒▒  b = ██████
a.reset():	a = (null)  b = ██████
swap(a, b):	a = ██████  b = (null)

何时使用

通常在以下情况下会用到std::optional

  • 当我们想很好地表示一个可能会为空的类型的时候。
  • 函数返回一些处理结果,该结果无法生成值,但该结果并不是错误。
  • 执行资源的延时加载。
  • 将可选参数传递到函数中。

使用示例

函数返回 std::optional

如果从函数返回可选值,则仅 std::nullopt 返回或计算值非常方便。

std::optional<std::string> TryParse(Input input)
{if (input.valid())return input.asString();return std::nullopt;
}
延时初始化

在某个类初始化的时候,由于某种原因,其某个成员还不能被初始化,也就是说该类初始化的时候需要选择性的初始化它的成员,其某个成员需要在稍晚时间或者在发生某个动作后才能够被初始化。如果我们要实现这种功能,使用optional会非常方便:

using T = /* some type */;struct S {optional<T> maybe_T;void construct_the_T(int arg) {// 我们无需处理重复构造所带来的问题,因为// optional的emplace member会自动销毁所// 之前存在的对象并构建一个新对象。maybe_T.emplace(arg);}T& get_the_T() {assert(maybe_T);return maybe_T.value();}// ... 接下来的拷贝和构造函数就能保证问题不会处在optional这里啦!...};

optional 特别适合延迟初始化问题,因为它本身就是延迟初始化的实例。所包含 T 的内容可以在构造时初始化,也可以在以后的某个时间初始化,或者永远不会初始化。任何包含 T 的内容都必须在销毁时 optional 销毁。

作为可选参数
#include <optional>
#include <iostream>class UserRecord
{
public:UserRecord (const std::string& name, std::optional<std::string> nick, std::optional<int> age): mName{name}, mNick{nick}, mAge{age}{}friend std::ostream& operator << (std::ostream& stream, const UserRecord& user);private:std::string mName;std::optional<std::string> mNick;std::optional<int> mAge;};std::ostream& operator << (std::ostream& os, const UserRecord& user) 
{os << user.mName << ' ';if (user.mNick) {os << *user.mNick << ' ';}if (user.mAge)os << "age of " << *user.mAge;return os;
}int main()
{UserRecord tim { "Tim", "SuperTim", 16 };UserRecord nano { "Nathan", std::nullopt, std::nullopt };std::cout << tim << "\n";std::cout << nano << "\n";
}

总结

对于std::optional我们注意以下几点:

  • std::optional 是表示“可为空”类型的包装器类型。
  • std::optional不会使用任何动态分配。
  • std::optional包含值或为空。
    • 使用 operator * operator-> value() value_or() 访问基础值。
  • std::optional 隐式转换为bool ,以便我们可以轻松检查它是否包含值。

当我们需要一个具有延迟初始化的对象、或者用来表达valueno value的时候,我们可以使用std::optional来将使用其类型提高抽象的级别,使其他人更加容易理解我们大代码在做什么,因为声明 optional<T> f(); void g(optional<T>);表达意图比做 pair<T, bool> f(); void g(T t, bool is_valid); 更清晰简洁。

文章首发公众号:iDoitnow如果喜欢话,可以关注一下


http://www.ppmy.cn/news/1171874.html

相关文章

springcloud笔记 (8) -网关 Gateway

网关 出国需要过海关 网关&#xff1a;网络的关卡 网关的作用 1&#xff1a;路由转发 2&#xff1a;安全控制 保护每个服务&#xff0c;不需要将每个暴露出去 3&#xff1a;负载均衡 1.没有网关&#xff1a;客户端直接访问我们的微服务&#xff0c;会需要在客户端配置很多…

SpringBoot整合redis实现过期Key监控处理(最简单模式)

前言&#xff1a;写这篇文章的目的主要是这方面的知识我是第一次实际运用到&#xff0c;在项目里面有个功能&#xff0c;需要登录的时候根据手机号发送短信验证码&#xff0c;我看了公司的代码是用redis过期key监控实现的&#xff0c;由于之前没有接触过这类&#xff0c;现在写…

分享一个逻辑题_一眼望去无法下手

1. 这道题的答案是 A.A B.B C.C D.D 2. 第 5 题的答案是 A.C B.D C.A D.B 3. 以下选项中哪一题的答案与其他三项不同 A. 第 3 题 B. 第 6 题 C. 第 2 题 D. 第 4 题 4. 以下选项中哪两题的答案相同 A. 第 1&#xff0c;5 题 B. 第 2&#xff0c;7 题 C. 第 1&#xff0c…

VUE父组件向子组件传递数据和方法

文章目录 1 父组件写法2 子组件写法 1 父组件写法 父组件参数和方法 data() {return {// 遮罩层loading: true,// 表格数据yfeList: []}}导入组件 import yfTable from "/views/yf/yfTable.vue";组件 components: {yfTabTable},传值使用 <yfTabTable :loadin…

AUTOSAR 包 MC-ISAR 安装指南

安装程序和Tresos配置概念适用于所有AURIX产品。 一、安装包命名规则 二、安装包定义 三、名词缩写 四、安装过程 以 BASE package 安装过程为例。 1、运行MC-ISAR_AS<xxx>_AURIX_TC<con>_<Step>_PB_BASE_V<nnn>.exe。 对于TC29x版本&#xff1a;运…

YMK_周报2

周报 读论文 投机采样 为什么大语言模型&#xff08;LLM&#xff09;的推理过程文本生成这么慢&#xff1f; 因为运行大型模型的前向传递很慢&#xff0c;你可能需要依次执行数百次迭代。那么为什么前向传递速度慢&#xff1f;前向传递通常以矩阵乘法为主。内存带宽是此操作的…

本地FTP YUM源报错处理

一、问题描述 某次OS升级到Anolis 8.6后&#xff0c;但是还需要centos 6.5的yum源&#xff0c;恢复回去后&#xff0c;yum更新&#xff0c;报如下错误&#xff1a; Errors during downloading metadata for repository ‘base’: Curl error (8): Weird server reply for ftp…

基于RM编译码的协作MIMO系统误码率matlab仿真,对比不同RM编译码参数

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2013b 3.部分核心程序 ...................................................................... [V1,N1,K1,I1] f…