【发布时间】:2018-01-26 05:03:34
【问题描述】:
此代码可以在 gcc 上正常使用,但它不适用于带有 clang 的 mac OS 该代码通过继承类型列表中的下一个类型来利用递归模板 考虑一个实体 => 头部和实体... => 尾部...
template<typename ...Entities>
struct GenericBidderCacheLoader;
template<typename Entity, typename ...Entities>
struct GenericBidderCacheLoader<Entity, Entities ...> : GenericBidderCacheLoader<Entities ...> {
using GenericBidderCacheLoader<Entities ...>::retrieve;
template<typename Config>
GenericBidderCacheLoader(const Config &config): GenericBidderCacheLoader<Entities...>(config), entity(config)
{}
void load() noexcept(false) {
entity.load();
GenericBidderCacheLoader<Entities...>::load();
}
template<typename T, typename... Keys>
decltype(std::declval<Entity>().retrieve(std::declval<T&>(),std::declval<Keys>()...), bool())
retrieve(T & t, Keys&& ... keys) {
return entity.template retrieve(t, std::forward<Keys>(keys)...);
}
Entity entity;
};
template<typename Entity>
struct GenericBidderCacheLoader<Entity> {
template<typename Config>
GenericBidderCacheLoader(const Config &config): entity(config)
{}
void load() noexcept(false) {
entity.load();
}
template<typename T, typename... Keys>
decltype(std::declval<Entity>().retrieve(std::declval<T&>(), std::declval<Keys>()...), bool())
retrieve(T & t, Keys&& ... keys) {
return entity.template retrieve(t, std::forward<Keys>(keys)...);
}
Entity entity;
};
基本上 GenericBidderCacheLoader 持有一个 typeist ,并且继承模型的工作方式类似于 GenericBidderCacheLoad GenericBidderCacheLoader 类型的用例在这里: 错误信息: 如果是 GCC 帮助GCC查看所有基类中定义的那些函数,但是clang放弃了看不到?
理想情况下,它应该如下工作,当替换失败 SFINAE 时,它应该能够在任何派生、base-I、base-II、base-III 类中看到函数。 完整的实现可以在 github 上的临时分支中找到
https://github.com/venediktov/vanilla-rtb/tree/ico_bidder20171217 我也尝试做递归来帮助Clang看到那些递归实例化的类函数 但它只有助于在类型列表中看到第二个而不是第三个,这几乎是我不得不从顶层递归到最终类型的情况。using CacheLoader = vanilla::GenericBidderCacheLoader<RefererEntity<>, ICOCampaignEntity<>, AdDataEntity<BidderConfig>>;
...
...
CacheLoader cacheLoader(config);
//Return from each lambda becomes input for next lambda in the tuple of functions
auto retrieve_referer_f = [&cacheLoader](const std::string& ref, auto&& ...) {
Referer referer;
if(!cacheLoader.retrieve(referer,ref)) {
return boost::optional<uint32_t>();
}
return boost::optional<uint32_t>(referer.ref_id);
};
auto retrieve_ico_campaign_f = [&cacheLoader](boost::optional<uint32_t> ref_id, auto&& ...) {
std::vector<ICOCampaign> ico_campains;
if (!cacheLoader.retrieve(ico_campains,*ref_id)) {
return boost::optional<decltype(ico_campains)>();
}
return boost::optional<decltype(ico_campains)>(ico_campains);
};
auto retrieve_campaign_ads_f = [&cacheLoader](boost::optional<std::vector<ICOCampaign>> campaigns, auto && req, auto && imp) {
std::vector<Ad> retrieved_cached_ads;
for (auto &campaign : *campaigns) {
if (!cacheLoader.retrieve(retrieved_cached_ads, campaign.campaign_id, imp.banner.get().w, imp.banner.get().h)) {
continue;
}
auto budget_bid = selector.authorize(cacheLoader.get_entity<CampaignCache<BidderConfig>>(), campaign.campaign_id);
std::transform(std::begin(retrieved_cached_ads),
std::end(retrieved_cached_ads),
std::begin(retrieved_cached_ads), [budget_bid](Ad & ad){
ad.auth_bid_micros = std::min(budget_bid, ad.max_bid_micros);
return ad;
});
}
if ( retrieved_cached_ads.empty() ) {
return boost::optional<decltype(retrieved_cached_ads)>();
}
return boost::optional<decltype(retrieved_cached_ads)>(retrieved_cached_ads);
};
error: no matching member function for call to
'retrieve'
if (!cacheLoader.retrieve(ico_campains,*ref_id)) {
~~~~~~~~~~~~^~~~~~~~
generic_bidder_cache_loader.hpp:42:9: note: candidate template ignored: substitution failure [with
T = std::__1::vector<ICOCampaign, std::__1::allocator<ICOCampaign> >, Keys = <unsigned int &>]: non-const lvalue reference to type 'Referer'
cannot bind to a value of unrelated type 'std::__1::vector<ICOCampaign, std::__1::allocator<ICOCampaign> >'
retrieve(T & t, Keys&& ... keys) {
using GenericBidderCacheLoader<Entities...>::retrieve
template<typename T, typename... Keys>
using retrieve_type = decltype(std::declval<Entity>().retrieve(std::declval<T&>(), std::declval<Keys>()...)) ;
template<typename T, typename... Keys>
typename std::enable_if<std::is_same<retrieve_type<T,Keys...>,bool>::value,bool>::type
retrieve(T & t, Keys&& ... keys) {
return entity.template retrieve(t, std::forward<Keys>(keys)...);
}
template<typename T, typename... Keys>
typename std::enable_if<std::is_same<typename GenericBidderCacheLoader<Entities ...>::template retrieve_type<T,Keys...>,bool>::value,bool>::type
retrieve(T & t, Keys&& ... keys) {
return GenericBidderCacheLoader<Entities ...>::retrieve(t, std::forward<Keys>(keys)...);
}
【问题讨论】:
-
你能提供 clang 错误吗?我尝试simplify the problem,但当仅限于模板成员函数时,clang 没有问题(可能是一些事情搞砸了)
-
无法复制,请发minimal reproducible example。
-
@vu1p3n0x 您的简化问题与 OP 的代码不同。事实上,clang++ 和 g++ 在这个问题上的表现确实不同。
-
@liliscent,感谢您创建最小、完整和可验证的示例!
标签: c++ templates c++14 sfinae llvm-clang