惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Stack Overflow Blog
Stack Overflow Blog
J
Java Code Geeks
Last Week in AI
Last Week in AI
人人都是产品经理
人人都是产品经理
博客园 - 【当耐特】
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
C
Check Point Blog
月光博客
月光博客
腾讯CDC
Engineering at Meta
Engineering at Meta
博客园 - Franky
Vercel News
Vercel News
D
Docker
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
F
Fortinet All Blogs
Microsoft Security Blog
Microsoft Security Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
雷峰网
雷峰网
Google DeepMind News
Google DeepMind News
Martin Fowler
Martin Fowler
GbyAI
GbyAI
B
Blog
Hugging Face - Blog
Hugging Face - Blog
T
Tailwind CSS Blog

Jia Yue Hua

完美转发不完美 闲散颂 adapting c++20 ranges algorithms for most metaprogramming Reproducible github Developer Environments 使用mpmcpipeline和jthread实现软流水 在其它线程周期回调函数 在当前线程周期回调函数 for_each transparent,为关联容器增加查找成员
cpo和tag_invoke
Jia Yue Hua · 2023-05-18 · via Jia Yue Hua

customization point object(cpo)和tag_invoke由eric niebler提出,在ranges和executor中有很多应用。 cpo可用于对库中的一些仿函数进行定制,而tag_invoke用于实现cpo,用于用户的类区分对于不同库的定制。

#include <gtest/gtest.h>
#include <folly/Utility.h>
#include <folly/lang/CustomizationPoint.h>
#include <folly/functional/Invoke.h>
template<class T>
struct Tag {
};

template<class T>
constexpr auto tag_c = Tag<T>{};
namespace A
{
struct FooCpo {
 template<typename T>
 auto operator()(Tag<T> t) const
     noexcept(folly::is_nothrow_tag_invocable_v<FooCpo, Tag<T> >)
     -> folly::tag_invoke_result_t<FooCpo, Tag<T>> {
   return folly::tag_invoke(*this, t);
 }
};
struct BarCpo {
     template<typename A>
     auto operator()(A&&a ) const
         noexcept(folly::is_nothrow_tag_invocable_v<BarCpo, A>)
         -> folly::tag_invoke_result_t<BarCpo, A> {
       return folly::tag_invoke(*this, (A&&)a);
     }
};
FOLLY_DEFINE_CPO(BarCpo, doathing)
FOLLY_DEFINE_CPO(FooCpo, dosomething)
}

namespace B
{
struct FooCpo {
 template<typename A>
 auto operator()(Tag<A> t) const
     noexcept(folly::is_nothrow_tag_invocable_v<FooCpo, Tag<A> >)
     -> folly::tag_invoke_result_t<FooCpo, Tag<A>> {
   return folly::tag_invoke(*this, t);
 }
};
FOLLY_DEFINE_CPO(FooCpo, dosomething)
}
namespace My
{
class SomeClass
{
  friend void tag_invoke(folly::cpo_t<A::dosomething>, Tag<SomeClass>)
  { std::cout << "A someclass\n";
  }
  friend void tag_invoke(folly::cpo_t<A::doathing>, const  SomeClass& some)
  { std::cout << "A doathing someclass\n";
  }
  friend void tag_invoke(folly::cpo_t<B::dosomething>, Tag<SomeClass>)
  { std::cout << "B someclass\n";
  }
};

}

TEST(cpo, basic)
{
  My::SomeClass c;
  A::doathing(c);
}
TEST(cpo, advance)
{
  A::dosomething(tag_c<My::SomeClass>);
  B::dosomething(tag_c<My::SomeClass>);
}

上文的 BarCpo 示范了如何定义一个cpo, BarCpo有一个模板成员operator(),内部调用tag_invoke, FOLLY_DEFINE_CPO(BarCpo, doathing) 帮我们定义了BarCpo类型的doathing cpo.

类My::SomeClass friend void tag_invoke(folly::cpo_t<A::doathing>, const SomeClass& some)实现了对A::doathing的定制。TEST(cpo,basic)中的A:::doathing(c)调用了我们实现的定制。

My::SomeClass 的友元void tag_invoke(folly::cpo_t<A::dosomething>, Tag)和 friend void tag_invoke(folly::cpo_t<B::dosomething>, Tag) 示范了对于不同名字空间A和B的dosomthing cpo,tag_invoke可方便的分别定制.