重庆门户网,泉州seo按天付费,学校网站模板html下载,免费网页推广一、Abominable Function Types
Abominable Function Types,令人讨厌#xff08;憎恶#xff09;的函数类型。这个在c的技术点中#xff0c;很少有人了解。那么什么是Abominable Function Types呢#xff1f;看下面的例子#xff1a;
using func void();
using func…一、Abominable Function Types
Abominable Function Types,令人讨厌憎恶的函数类型。这个在c的技术点中很少有人了解。那么什么是Abominable Function Types呢看下面的例子
using func void();
using func_aft void() const volatile ;在上面的两行代码中声明了两个函数。第一行的代码大家一般都比较熟悉一般函数都这样声明。但下面一行的代码就比较不一般了它带了const、volatile和 等限定符。要知道限定符可是在成员函数中才能使用的它隐式调用了*this,可这里偏偏它又是一个特定的函数类型而不类成员这就有一个问题了没有办法指定它的所属类。 换句话说根本没办法实现了一个这样的函数只是有一种想象罢了。举个不恰当的例子“我要去火星”这个想法没错但实现不了至少目前实现不了。 同时如果想声明一个此种类型的指针和引用时会报一个“ill-formed”错误即下面的代码
using p func_aft*;
using r func_aft;这种函数就是一个令人讨厌的函数类型一般来说这种类型都具有这个特征特定的函数带有限定符。 那它有什么用呢
二、作用
先铺垫一下引用限定符和const。在早期的开发中如果不想让某个变量被改变那么可以使用如下的方法来操作
void Test(const A a)
{//此处无法修改A的成员值
}在c11中其实引进了另外一种方式也就是,,看下面的例子
#include iostreamclass T {
public:T(int n):n_(n){}int get(){return this-n_;}
private:int n_;
};
int main() {T t(1);std::cout t.get() std::endl; // OK//std::cout std::move(t).get() std::endl; // errorreturn 0;
}同理右值也可以使用上面的代码只是把改成即可。效果也会发生变化左值就无法使用了只能使用右值。这时如果想实现上面早期的方式可以增加const注意const一定要在和之前
#include iostreamclass T {
public:T(int n,int n1):n_(n),n1_(n1){}int get()const {return this-n_;}int getr()const {return this-n1_;}
private:int n_;int n1_
};不过此时需要注意的是const 修饰时此时的值可以是左值也可以是右值和单纯引用限定时有区别。而const 时仍然只能是右值。 好介绍完了背景知识回到正题。Abominable Function Types有什么作用 从一个例子开始说明在c11中引入了std::function这个对象那么可以任意声明一个变量如下
struct T
{void operator()() {/* ... */} // not const!
};
const std::functionvoid() func(T{});
func(); // OK在std::function其本身的operator()它是一个常函数但T的是一个普通函数这样一个常量就可以调用一个非常量函数那么它在多线程执行时就无法达到要求的不产生况态条件。此时就可以用Abominable Function Types来处理它即只有拿到的函数类型为const才构建需要的对象。这个在c23中的move_only_function就是如此做的。
三、实际的应用
在看到上面的分析和说明后就可以看看它在实际工程中到底有什么作用先说明一点它基本上都是在模板元编程用的其它方向上确实非常非常少。在Traits类型时这些约束应用到引用和指针时就需要额外处理这种令人讨厌的函数类型。
template typename TYPE
constexpr bool is_function_v false;template typename RESULT, typename ...ARGS
constexpr bool is_function_vRESULT(ARGS...) true;template typename RESULT, typename ...ARGS
constexpr bool is_function_vRESULT(ARGS......) true;template typename RESULT, typename ...ARGS
constexpr bool is_function_vRESULT(ARGS...) true;template typename RESULT, typename ...ARGS
constexpr bool is_function_vRESULT(ARGS......) true;template typename RESULT, typename ...ARGS
constexpr bool is_function_vRESULT(ARGS...) true;template typename RESULT, typename ...ARGS
constexpr bool is_function_vRESULT(ARGS......) true;template typename RESULT, typename ...ARGS
constexpr bool is_function_vRESULT(ARGS...) const true;template typename RESULT, typename ...ARGS
constexpr bool is_function_vRESULT(ARGS......) const true;template typename RESULT, typename ...ARGS
constexpr bool is_function_vRESULT(ARGS...) const true;template typename RESULT, typename ...ARGS
constexpr bool is_function_vRESULT(ARGS......) const true;template typename RESULT, typename ...ARGS
constexpr bool is_function_vRESULT(ARGS...) const true;template typename RESULT, typename ...ARGS
constexpr bool is_function_vRESULT(ARGS......) const true;template typename RESULT, typename ...ARGS
constexpr bool is_function_vRESULT(ARGS...) volatile true;template typename RESULT, typename ...ARGS
constexpr bool is_function_vRESULT(ARGS......) volatile true;template typename RESULT, typename ...ARGS
constexpr bool is_function_vRESULT(ARGS...) volatile true;template typename RESULT, typename ...ARGS
constexpr bool is_function_vRESULT(ARGS......) volatile true;template typename RESULT, typename ...ARGS
constexpr bool is_function_vRESULT(ARGS...) volatile true;template typename RESULT, typename ...ARGS
constexpr bool is_function_vRESULT(ARGS......) volatile true;template typename RESULT, typename ...ARGS
constexpr bool is_function_vRESULT(ARGS...) const volatile true;template typename RESULT, typename ...ARGS
constexpr bool is_function_vRESULT(ARGS......) const volatile true;template typename RESULT, typename ...ARGS
constexpr bool is_function_vRESULT(ARGS...) const volatile true;template typename RESULT, typename ...ARGS
constexpr bool is_function_vRESULT(ARGS......) const volatile true;template typename RESULT, typename ...ARGS
constexpr bool is_function_vRESULT(ARGS...) const volatile true;template typename RESULT, typename ...ARGS
constexpr bool is_function_vRESULT(ARGS......) const volatile true;*代码摘自Alisdair Meredith, ameredith1bloomberg.net论文《Abominable Function Types》 上面的代码用来处理各种情况下的函数类型的判断可以测试所有能想到的函数类型保证模板的安全。 下面再看一个可能在实际中遇到的情况
template typename T
struct remove_member_pointer { using type T; };template typename T, typename classType
struct remove_member_pointerT classType::* { using type T; };
struct T {void test() { std::cout abc std::endl; };
};
using mfType typename remove_member_pointerdecltype(T::test)::type;看一下c的STL中remove_pointer的可能实现
template class T struct remove_pointer {typedef T type;};
template class T struct remove_pointerT* {typedef T type;};
template class T struct remove_pointerT* const {typedef T type;};
template class T struct remove_pointerT* volatile {typedef T type;};
template class T struct remove_pointerT* const volatile {typedef T type;};在上面的代码去除上一层的T*是非常容易理解的而去除函数指针中的classType可能有点不好理解classType::*可以代表其任意的成员函数在实际的remove_member_pointer过程中只是提供了一个typedef的函数指针这里如果有不明白的可以看一下函数指针中如何使用typedef这个在std::add_pointer中也有体现“Otherwise (if T is a cv- or ref-qualified function type), provides the member typedef type which is the type T.The behavior of a program that adds specializations for std::add_pointer is undefined.”
四、总结
今天分析的这个令人讨厌的函数类型和c11中的引用限定符都是比较少使用的在实际工程中估计绝大多数国内的c程序员都无法用到。那就了解一下省得再看国外的框架代码时遇到这样的问题搞不清楚。 消除这种令人讨厌的函数类型有很多种最简单的就是禁止它们。但这又无法兼容旧得版本标准这本身就是一个非常不好体验。那么只能选择完善它在c23中就对其进行了处理比如使用this(前面分析过的Deducing This)来处理一些等效的操作等。 一个知识存在一定有其存在的意义当确实遇到需要它的问题时才会发现确实是有用。