C++如何在指定命名空间内实现用户自定义定制点功能
解决方案
核心结论
- 在C++11、14、17标准下完全可以实现你要的「优先匹配指定custom命名空间下的定制实现」需求,不需要侵入全局命名空间。
第一个方案的问题修复
你之前注释掉using custom::print;触发报错,是因为你在custom命名空间中定义了未实现的模板函数声明template <typename T> void print(const T&);,一旦重载决议匹配到该模板就会报未定义符号错误。只要删掉这个无用的前置声明,就能正常工作。
修正后的完整可运行代码如下:
#include <iostream> namespace custom { // 删掉原有未实现的模板前置声明即可 } namespace eld { namespace detail { template<typename T> void print(const T &) { std::cout << "Generic version" << std::endl; } struct print_fn { template<typename T> void operator()(const T &t) const { using custom::print; using detail::print; // 引入通用兜底实现参与重载决议 print(t); } }; template<typename T> struct static_constexpr { static constexpr T value{}; }; template<typename T> constexpr T static_constexpr<T>::value; } namespace { constexpr const auto &print = detail::static_constexpr<detail::print_fn>::value; } } struct foo { }; namespace custom { // 现在这个实现会被优先匹配 void print(foo) { std::cout << "Custom Implementation for foo" << std::endl; } struct bar{}; void print(bar) { std::cout << "Custom implementation with ADL for custom::bar" << std::endl; } } // 全局的print不会被优先调用,避免了命名冲突 void print(foo) { std::cout << "Implementation for foo" << std::endl; } int main(int, char **) { eld::print(4); eld::print(foo()); eld::print(custom::bar()); return 0; }
运行输出完全符合预期:
Generic version Custom Implementation for foo Custom implementation with ADL for custom::bar
两种定制方案的选择建议
- 如果你偏好函数重载的定制方式:用上面修正后的方案即可,用户只需要在
custom命名空间下实现对应类型的print重载,不需要处理模板特化语法,使用门槛更低。 - 如果你偏好类模板特化的方式:只需要把
eld::custom::print类模板的定义放到你的库的公开头文件中,用户包含头文件后就可以直接特化,不需要自己复制粘贴前置声明,不存在你提到的使用不便问题。
内容的提问来源于stack exchange,提问作者Sergey Kolesnik
相关产品推荐
相关产品推荐

