我想编写一个unmarshaller来提取存储在msgpack数组中的参数,用于调用sigc::signal::emit(...)
的各个参数。我试过这个:
template<class... T> class MsgpackAdapter: public MsgpackAdapterBase {
public:
MsgpackAdapter (sigc::signal<void, T...> &sig)
: MsgpackAdapterBase (), signal_ (sig)
{}
protected:
virtual void do_emit (const msgpack::object_array &mp_args) override;
private:
sigc::signal<void, T...> signal_;
};
template<class T1>
void MsgpackAdapter<T1>::do_emit (const msgpack::object_array &mp_args)
{
T1 a1;
mp_args.ptr[0].convert (a1);
signal_.emit (a1);
}
template<class T1, class T2>
void MsgpackAdapter<T1, T2>::do_emit (const msgpack::object_array &mp_args)
{
T1 a1;
T2 a2;
mp_args.ptr[0].convert (a1);
mp_args.ptr[1].convert (a2);
signal_.emit (a1, a2);
}
以及最多4个参数。但我收到此错误消息(来自使用clang 3.9的vim-youcompleteme):
'MsgpackAdapter<T1>::' for declaration does not refer into a class, class template or class template partial specialization
似乎我可以对整个班级进行部分专业化:
template<class T1> class MsgpackAdapter<T1>: public MsgpackAdapterBase { ... };
但我宁愿能够专注于emit
方法来减少复制量和放大倍数。粘贴代码。我错过了明显的东西吗?我认为主要的困难是do_emit
没有采用模板化的论点。
另一个好奇心是,如果我在没有可变参数模板的情况下尝试这样做,并使用:
template<class T1> class MsgpackAdapter: public MsgpackAdapterBase { ... };
template<class T1, class T2> class MsgpackAdapter: public MsgpackAdapterBase { ... };
我收到第二个类定义与第一个类冲突的错误。这是可以理解的,但我想知道sigc如何在没有可变参数模板的情况下管理类似的东西。
答案 0 :(得分:2)
我一直觉得专门用于成员函数的最可维护的方法是遵循一个专门的函数对象:
Imports Microsoft.Office.Interop
Public Class Form1
Public WithEvents myIns As Outlook.Inspector
Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
Process.Start("Outlook.exe")
Threading.Thread.Sleep(3000)
Dim olApp As New Outlook.Application
Dim myMailItem As Outlook.MailItem
myMailItem = CType(olApp.CreateItem(Outlook.OlItemType.olMailItem), Outlook.MailItem)
myMailItem.Subject = "Hello"
myMailItem.To = "anybody@example.com"
myMailItem.Body = "Hi there..."
Dim myIns As Outlook.Inspector
myIns = myMailItem.GetInspector
myIns.Display(False)
Dim myWord As Word.Document
myWord = CType(myIns.WordEditor, Word.Document)
Dim mySel As Word.Selection
mySel = myWord.Application.Selection
Threading.Thread.Sleep(10000)
'Following line just for testing. Normally following line doesnt exist in my original code. The real scenario is the user minimizes the inspector manually.
myIns.WindowState = Outlook.OlWindowState.olMinimized
myWord.InlineShapes.AddPicture(FileName:="C:\Example.png", LinkToFile:=False, SaveWithDocument:=True, Range:=mySel.GoTo(What:=Word.WdGoToItem.wdGoToLine, Which:=Word.WdGoToDirection.wdGoToLast, Count:=-4))
'myMailItem.Send()
End Sub
End Class
答案 1 :(得分:1)
In C++14:
template<class F>
auto foreach( F&& f ) {
return [f=std::forward<F>(f)](auto&&...args)mutable{
using discard=int[];
(void)discard{0,(void(
f(decltype(args)(args))
),0)...};
};
}
template<std::size_t...Is>
auto index_over( std::index_sequence<Is...> ) {
return [](auto&& f)->decltype(auto){
return decltype(f)(f)( std::integral_constant<std::size_t, Is>{}... );
};
}
template<std::size_t N>
auto index_upto( std::integral_constant<std::size_t, N> ={} ) {
return index_over( std::make_index_sequence<N>{} );
}
template<class...Ts>
void MsgpackAdapter<Ts...>::do_emit (const msgpack::object_array &mp_args)
{
std::tuple<Ts...> args;
index_upto<sizeof...(Ts)>()(
foreach(
[&](auto I){
mp_args.ptr[I].convert(std::get<I>(args));
}
)
);
index_upto<sizeof...(Ts)>()(
[&](auto...Is){
signal_.emit(std::get<Is>(args)...);
}
);
}
基本上,做一个元组。
在该元组中创建一组索引。
对于元组中的每个索引,请调用convert。
然后,调用emit获取元组的每个元素。
有很多关于堆栈溢出的代码示例,涉及将元组的每个参数传递给函数调用。那是发射部分。
关于为元组的每个元素做某事的堆栈溢出有很多例子。使用索引这样做有点棘手,但在最坏的情况下,你可以计算每个元素是否按顺序执行。
这些可以在C ++ 11中完成,但在C ++ 14中,我可以在没有辅助函数的函数中完成所有操作。
上述魔术代码的描述。 index_upto
返回一个lambda。这个lambda接受另一个lambda,然后用编译时常量从0到N-1调用它。它通过调用index_over
执行此操作,该foreach
采用索引列表。
index_upto
需要一个lambda f。然后它返回一个带有任意数量参数的lambda,并用这些参数中的每一个调用f一次。它的实现是一个涉及参数包和数组初始化的深度mojo。
通过撰写foreach
和0
,您可以为N-1
到.convert
的每个编译时值执行某些操作。我们称之为index_upto
。
只需致电emit
,我们就可以立即将所有参数传递给ssh-add -A
。
我们可以在C ++ 11中做类似的事情,但我们会编写带有参数包等的辅助函数。这不仅仅是一种痛苦。