ue4 SNew补遗
上一篇分析了SNew背后的实现,但是有一个关键问题遗漏了,那就是:
#define SNew( WidgetType, ... ) \
MakeTDecl<WidgetType>( #WidgetType, __FILE__, __LINE__, RequiredArgs::MakeRequiredArgs(__VA_ARGS__) ) <<= TYPENAME_OUTSIDE_TEMPLATE WidgetType::FArguments()
为何这里要用一个特别奇怪的操作符重载:【<<=】??
这个宏的目的无非是包装了WidgetType实例的创建和初始化,为何不用一个InitFromArg(FArguments& arg)之类的常规成员函数呢?
要解释这个问题,可以看下面一段示例代码:
TSharedRef<SOverlay> ViewportOverlayWidgetRef = SNew( SOverlay ); TSharedRef<SGameLayerManager> GameLayerManagerRef = SNew(SGameLayerManager)
.SceneViewport_UObject(this, &UGameEngine::GetGameSceneViewport, GameViewportClient)
.UseScissor(false)
[
ViewportOverlayWidgetRef
];
上面两句代码,都是用SNew创建一个新对象,一个不带参数,一个带了一串链式调用,要支持后者的写法,就是使用【<<=】的目的。
首先,要看清楚这一串链式调用所作用的对象:是FArgment而非WidgetType!
三个调用:SceneViewport_UObject、UseScissor和operator[],分别是用SLATE_ATTRIBUTE、SLATE_ARGUMENT、SLATE_DEFAULT_SLOT三个宏生成的。
然而更重要的是它们都包在SLATE_BEGIN_ARGS/SLATE_END_ARGS之间,而这一对宏就是在WidgetType类里再定义一个内嵌类:
#define SLATE_BEGIN_ARGS( WidgetType ) \
public: \
struct FArguments : public TSlateBaseNamedArgs<WidgetType> \
{ \
typedef FArguments WidgetArgsType; \
FORCENOINLINE FArguments() #define SLATE_END_ARGS() \
};
这就是说链式调用不可能发生成SNew返回的Widget实例上,如果SNew真的是先返回一个Widget,那代码就大大有误了,连编译都过不了。
然而事实是一切顺利,那上述矛盾如何解决的呢?回过头看一下SNew展开那句代码的最后,是没有分号【;】的!这就给SNew()后面的代码提供了一个奇妙的组合结果!
就比如说下面这句话:
SNew(SGameLayerManager).UseScissor(false);
展开后成为:(简化)
MakeTDecl<SGameLayerManager>() <<= SGameLayerManager::FArguments().UseScissor(false);
一下子就高能了!因为操作符【<<=】的优先级是非常低的,这将导致它后面的代码被先结合起来,运算完了之后再整体做为【<<=】的参数传给前方的Widget实例。
而结合上面提到的链式调用都会返回this,所以后面不管跟多少调用,最终得到的结果都还是一个FArgument对象,恰恰是【<<=】所需要的类型。
此处的巧妙就在于,做为原本在同一个宏(SNew)里定义的三段:Widget <<= FArgument,在最终代码里并没有形成一体,而是利用:
1、<<=的低级先级
2、末尾没带分号
使FArgument与之后的代码优先结合,完成了一连串的链式调用后,再做为整体返还。
现在回到最初的问题:如果不使用操作符重载,而是一个普通的InitFromArg函数,会发生什么情形:
MakeTDecl<WidgetType>(SGameLayerManager).InitFromArg(SGameLayerManager::FArguments()).UseScissor(false);
显然不可能再优先后结合了。
附:SLATE_ATTRIBUTE
SLATE_ATTRIBUTE展开后,生成一个TAttribute< AttrType >成员,及大量对此属性赋值的方法,而此例中带_UObject后缀的版本,则是将其绑定到一个UObject类的成员函数上:
#define SLATE_ATTRIBUTE( AttrType, AttrName ) \
TAttribute< AttrType > _##AttrName; \ template< class UserClass, typename Var1Type > \
WidgetArgsType& AttrName##_UObject( UserClass* InUserObject, typename TAttribute< AttrType >::FGetter::template TUObjectMethodDelegate_OneVar_Const< UserClass, Var1Type >::FMethodPtr InFunc, Var1Type Var1 ) \
{ \
_##AttrName = TAttribute< AttrType >::Create( TAttribute< AttrType >::FGetter::CreateUObject( InUserObject, InFunc, Var1 ) ); \
return this->Me(); \
} \
ue4 SNew补遗的更多相关文章
- ue4 SNew背后的逻辑
ue4的ui库Slate体系非常庞大,即使是在创建对象这一小事上,也是相当复杂: SLATECORE_API TSharedRef<SWidget> SNullWidget::NullWi ...
- Houdini技术体系 基础管线(四) :Houdini驱动的UE4植被系统 下篇
背景 在上篇中,实现了使用Houdini在UE4里根据地形过程生成植被的最基本的原型.并且支持把植被在UE4里Bake成使用的HierarchicalInstancedStaticMeshCompon ...
- UE4之Slate:App默认窗口的创建流程
UE4版本:4.24.3源码编译 Windows10 + VS2019开发环境 在先前分享的基础上,现在来梳理下App启动时默认窗口的创建流程,以及相关的类.对象之间的抽象层级: 纯C++工程配置 S ...
- UE4之Slate: SImage
概述 距离上次记录<UE4之Slate:纯C++工程配置>后已经好长时间了: 这个随笔来记录并分享一下SImage控件的使用,以在屏幕上显示一张图片: 目标 通过SImage控件的展示,学 ...
- UE4自动打包工具编写
在UE的开发中,有些项目需要针对不同版本出不同的包,并有一个对应的GUI界面,供大家使用. 1.插件编写 先使用UE4自己的插件模板创建插件,做成插件形式 然后注册Slate UI,编写打开逻辑.并在 ...
- UE4新手引导之下载和安装虚幻4游戏引擎
1) 进入虚幻4的官方主页(https://www.unrealengine.com/) 这里你可以获得关于虚幻4的最新资讯,包括版本更新.博客更新.新闻和商城等.自2015年起,该引擎已经提供免费下 ...
- UE4新手引导入门教程
请大家去这个地址下载:file:///D:/UE4%20Doc/虚幻4新手引导入门教程.pdf
- ue4 c++学习推荐
我由易到难推荐,不过在此之前还是先看看官方对于VS设置的推荐: https://docs.unrealengine.com/latest/INT/Programming/Development/Vis ...
- 如何创建独立的UE4服务端
原文作者:@玄冬Wong 转载请注明原文出处:http://aigo.iteye.com/blog/2268777 这是论坛上对UE服务端功能的回答,意思是UE4提供了主流MMO网游服务端所具备的特性 ...
随机推荐
- Provisional, Temporary 和Interim 的区别
1 Provisional adj. 临时的.暂时的.暂定的:n. 临时邮票 强调在一定时期内暂时的.双方同意的但还不是最终确定的决定或者条约等. Such as例如: Provisional go ...
- a+=b 是什么意思?
a+=b或者-=,*=等等就是相当于a=a+b;简写而已,没什么特殊含义此外还有a++/a--相当于a=a+1/a=a-1
- Windows下配置nginx根目录的问题
location / { root E:/xampp/htdocs/html5/php/yii2-rest-master/rest/web; index index.html index.htm; } ...
- Codeforces Round #229 (Div. 2) D
D. Inna and Sweet Matrix time limit per test 1 second memory limit per test 256 megabytes input stan ...
- JS-改变页面的颜色(三)
需求:点击页面的按钮,改变页面的颜色 思路:一先画出最简单的页面,二想办法获取页面的body节点,三想办法修改body节点的背景颜色属性,四通过一个方法获取随机的颜色值 和第二个例 ...
- JS中插入节点的方法appendChild和insertBefore的应用
1.appendChild() 方法:可以向节点的子节点列表的末尾添加新的子节点.比如:appendChild(newchild)括号里可以是创建的标签var newchild = document. ...
- mac java目录
/Library/Java/JavaVirtualMachines/jdk1.7.0_10.jdk/Contents/Home mac java的安装目录为 /Library/Java/JavaVir ...
- margin:0 auto在IE中失效的解决方案
转自:http://www.cnblogs.com/hongchenok/archive/2012/11/29/2795041.html 最近在开发项目的时候,发现在火狐浏览器中设置外容器margin ...
- myeclipse 导入JAVA项目
说白了.就是别人给你一份写好的文件你不会用是吧?新手都是这样的.很正常..这样.咱们一步一步的来.邮件项目工程栏,选择import,选择General,选择Existing Projects into ...
- Python 2.7_First_try_爬取阳光电影网_20161206
之前看过用Scrapy 框架建立项目爬取 网页解析时候用的Xpath进行解析的网页元素 这次尝试用select方法匹配元素 1.入口爬取页面 http://www.ygdy8.com/index.ht ...