如何解决能够采用第三方依赖项的最佳扩展机制?
template <class T> concept Initable = requires (T&t) { { init(t) }; };
// just for demonstration purposes,real concept makes more sense ...
并且我想为像 std::optional
这样的第三方类提供一个采用层来实现这个概念,对我来说最简单的方法是什么?
显然,下面这段代码失败了:
template <std::semiregular T>
T& init(std::optional<T> &v) { /* contents not that important */ v = T{}; return *v; }
static_assert(Initable<std::optional<int>>,"Oh no!"); // Fails!
原因是两阶段查找。
在第 1 阶段尝试解析 init
概念中的 Initable
时,我对 init
的定义不可用,因为它在下面提供{1}} 概念。
在第 2 阶段尝试解决它时,通过依赖参数的查找找不到我的定义,因为 Initable
命名空间中没有提供它。
因此,两个明显的解决方案是在定义 std
概念之前提供 init
的定义或将 Initable
移至 init
命名空间。
但我想在没有
的情况下为std
实现这个概念
这样做的最佳方法是什么?在定义 std
概念时,我是否可以更轻松地完成此操作?
基本上我是问,this 可能吗?
Initable
如果没有,下一个最好的事情是什么?
解决方法
解析为模板实例化期间可见的任何函数显然违反了两阶段查找的原则。我决定采用不同的方法,并使用在单独的自定义命名空间中定义的虚拟参数:
namespace CP { // CP = CustomizationPoint
struct Token {};
}
现在可以在 init
命名空间或命名空间中定义 CP
函数,对象定义在:
namespace std {
template <class T> void init(std::optional<T> &v,CP::Token) { ... }
// illegal,but works -- do not declare stuff in namespace std.
}
namespace CP {
template <class T> void init(std::optional<T> &v,CP::Token) { ... }
}
这已经很不错了。如果 std
命名空间中的定义不需要 CP::Token
参数,那就更好了。这可以通过提供一个将解析为正确函数的函数对象来完成(类似于引入标准库的自定义点对象):
constexpr inline struct {
template <class T>
auto operator()(std::optional<T>& v,CP::Token t) const
-> decltype(init(v,t),[]{}())
{
init(v,t);
}
template <class T>
auto operator()(std::optional<T>& v,...) const
-> decltype(init(v),[]{}())
{
init(v)
}
} init;
这个函数对象有点庞大,但它会解析为带有 CP::Token
参数的变体(如果可用),否则回退到没有令牌参数的变体(如果该参数可用)。
对我来说,这似乎是一种非常明智的方法,可以完美扩展,甚至允许我们覆盖已经具有正确名称但语义错误的实现。
必须稍微修改概念才能使其工作:
template <class T> concept Initable = requires (T&t) { init(t,CP::Token{}); };
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。