<div dir="ltr">I'd probably still vote in favor of a lambda, even if it made the iterator type unutterable - do you have an example where that makes things especially difficult to read?</div><br><div class="gmail_quote"><div dir="ltr">On Mon, Jul 30, 2018 at 3:37 PM Hamza Sood via Phabricator via llvm-commits <<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">hamzasood created this revision.<br>
hamzasood added reviewers: dexonsmith, fhahn, chandlerc, timshen.<br>
Herald added a subscriber: llvm-commits.<br>
<br>
This patch adds a simple type that lets you create a functor from a function at compile time.<br>
<br>
While working on Clang, I needed a way to create an `llvm::filter_iterator` that filters based on the dynamic type as determined by `llvm::isa`. As far as I'm aware, the best way to do this currently (without lambdas as they'd make the iterator type unutterable) is:<br>
<br>
  llvm::make_filter_range(MyRange, static_cast<bool(*)(Base *)>(&isa<Derived>))<br>
<br>
That's problematic because the iterator object ends up storing a function pointer; if the compiler can't follow the iterator's path from creation to use then it probably won't be able to get round the unnecessary indirection. This new type solves that by storing the function address as part of the object type, so there's no runtime overhead.<br>
<br>
<br>
Repository:<br>
  rL LLVM<br>
<br>
<a href="https://reviews.llvm.org/D50021" rel="noreferrer" target="_blank">https://reviews.llvm.org/D50021</a><br>
<br>
Files:<br>
  include/llvm/ADT/STLExtras.h<br>
  unittests/ADT/STLExtrasTest.cpp<br>
<br>
<br>
Index: unittests/ADT/STLExtrasTest.cpp<br>
===================================================================<br>
--- unittests/ADT/STLExtrasTest.cpp<br>
+++ unittests/ADT/STLExtrasTest.cpp<br>
@@ -364,4 +364,21 @@<br>
   EXPECT_EQ(5, count);<br>
 }<br>
<br>
+int g() { return 42; }<br>
+void g(int &&) { }<br>
+<br>
+TEST(STLExtrasTest, static_fptr) {<br>
+  {<br>
+    static_fptr<int(), g> obj;<br>
+    EXPECT_EQ(obj(), 42);<br>
+  }<br>
+<br>
+  // Check for perfect forwarding of the parameters.<br>
+  {<br>
+    static_fptr<void(int &&), g> obj;<br>
+    int i = 0;<br>
+    obj(std::move(i));<br>
+  }<br>
+}<br>
+<br>
 } // namespace<br>
Index: include/llvm/ADT/STLExtras.h<br>
===================================================================<br>
--- include/llvm/ADT/STLExtras.h<br>
+++ include/llvm/ADT/STLExtras.h<br>
@@ -135,6 +135,26 @@<br>
   operator bool() const { return callback; }<br>
 };<br>
<br>
+/// A simple functor that just calls a function specified at compile time.<br>
+/// Unlike storing a function pointer, this has zero runtime overhead because<br>
+/// the function address is part of the object type.<br>
+///<br>
+/// Example usage:<br>
+///     void f();<br>
+///<br>
+///     static_fptr<void(), f> obj;<br>
+///     obj();<br>
+template<typename T, T *Fn,<br>
+         typename = typename std::enable_if<std::is_function<T>::value>::type><br>
+struct static_fptr {<br>
+  template<typename... Args><br>
+  auto operator()(Args &&... args) const<br>
+      noexcept(noexcept(Fn(std::forward<Args>(args)...)))<br>
+      -> decltype(Fn(std::forward<Args>(args)...)) {<br>
+    return Fn(std::forward<Args>(args)...);<br>
+  }<br>
+};<br>
+<br>
 // deleter - Very very very simple method that is used to invoke operator<br>
 // delete on something.  It is used like this:<br>
 //<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div>