不那么新的modern C++简要学习笔记 logo 不那么新的modern C++简要学习笔记

编译器支持最低版本要求:

  • GCC: 5.0
  • MSVC: 19.0
  • Clang: Yes

提案: N3462

std::result_of是C++11标准中提供的一种类型萃取工具,用于获取函数调用结果的类型,它的定义如下:

template <class F, class... Args>
class result_of<F(Args...)>;

其中,F是函数类型,Args是参数类型。std::result_of<F(Args...)>将返回函数调用表达式f(args...)的返回类型。例如:

int func(double d, int i) { return d * i; }
using result_type = std::result_of<decltype(func)&(double, int)>::type;
static_assert(std::is_same<result_type, int>::value, "result type should be int");

上述代码中,std::result_of<decltype(func)&(double, int)>::type返回了函数func在调用时的返回类型,即int。这样我们就可以在编译时获取函数调用表达式的返回类型,进而实现更加灵活和复杂的模板元编程。

std::result_of的实现依赖于SFINAE技术。在调用std::result_of<F(Args...)>时,编译器会先尝试调用一个辅助函数,该函数接收一个参数类型为F,参数类型为Args...的参数列表,然后根据调用结果的类型,推导出std::result_of<F(Args...)>的返回类型。如果调用辅助函数失败,编译器会尝试使用其他函数重载,直到找到匹配的函数。

SFINAE技术是通过函数重载和模板参数推导失败来实现的。在调用一个函数时,编译器会首先进行函数匹配,尝试找到与函数调用参数类型和个数最匹配的函数。如果找到了匹配的函数,则调用该函数。否则,编译器会尝试使用其他函数重载,如果所有的函数重载都无法匹配,则编译器将会报错。

SFINAE技术通过在模板参数推导时失败来实现函数重载的选择。例如,如果在模板参数推导时某个参数类型无法匹配,编译器会认为这个模板实例化不可行,并尝试使用其他模板实例化。这样就可以根据不同的模板实例化,选择不同的函数重载。

因此,在使用std::result_of和SFINAE技术时,需要注意模板参数推导的情况,以避免出现不必要的错误。同时,需要了解模板元编程的相关知识,以便更好地理解这些技术的实现原理。

SFINAE

SFINAE是C++模板元编程中的一种技术,全称为Substitution Failure Is Not An Error,即“替换失败不是一个错误”。这个技术是指在编译时,如果模板实例化的过程中发生了替换失败的情况,编译器不会报错,而是会尝试使用其他的模板实例化,这样就可以通过一系列判断选择最合适的模板实例。

SFINAE通常用于解决函数重载中的一些问题。在C++中,函数重载是通过函数的参数类型和个数来区分的。当函数调用时,编译器会尝试匹配所有可行的重载函数,如果找到了匹配的函数,就会调用该函数。但是,当函数重载的参数类型过于复杂,或者函数模板的参数类型不确定时,编译器可能无法确定最佳匹配的函数。这时,SFINAE技术就可以派上用场了。

SFINAE的实现通常是通过模板参数推导失败来实现的。例如,假设我们有一个模板函数,用于检查某个类型是否具有一个成员函数:

template <typename T>
struct has_member_function_foo {
    template <typename U>
    static auto test(U* p) -> decltype(p->foo(), std::true_type{});
    static auto test(...) -> std::false_type;
    static constexpr bool value = decltype(test((T*)nullptr))::value;
};

这个模板函数中,我们使用了两个重载的test函数。第一个test函数尝试访问T类型的一个名为foo的成员函数,如果可以访问,则返回一个std::true_type类型的值。第二个test函数是一个catch-all函数,用于处理访问T类型的foo成员函数失败的情况。在实际调用时,我们可以使用类似下面的方式来判断某个类型是否具有一个名为foo的成员函数:

struct A { void foo() {} };
struct B {};

static_assert(has_member_function_foo<A>::value == true, "A has foo");
static_assert(has_member_function_foo<B>::value == false, "B doesn't have foo");

在上面的示例中,我们使用static_assert语句来检查是否能够访问某个类型的foo成员函数。如果访问成功,则has_member_function_foo的value成员将被设置为true,否则将被设置为false

需要注意的是,SFINAE技术需要谨慎使用,因为它可能会导致模板实例化的过程变得非常复杂。在实际使用中,建议使用简单的技巧,比如函数重载和if constexpr语句,来实现类似的功能。

感觉不错,小额赞助一下!
missdeer WeChat Pay

微信扫一扫

missdeer AliPay

支付宝扫一扫

Hosted by Netlify, 本站由 @missdeer 创建,由 Jekyll 于 2024-03-12 生成,感谢 CloudCannon 制作的theme: Edition ,感谢 Let's Encrypt 提供免费的SSL证书服务。本站点采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。© 2017 - 2024