如何制作函数模板仅适用于特定命名空间中的类型?

时间:2017-03-19 06:36:09

标签: c++ c++11 templates namespaces

我有一个名称空间my_space并将函数模板定义为

namespace my_space
{
    template<class T>
    ostream operator<<(ostream& os, T const& t)
    { ... }
}

我希望此功能仅适用于my_space中的我的课程,或者对于my_space以外的某些类型可能会有歧义。例如

namespace my_space
{
     void f()
     {
           cout << "test"; //overload ambiguous
      }
}

有什么方法可以避免这种情况吗?

1 个答案:

答案 0 :(得分:2)

我们可以通过一些ADL(依赖于参数的查找)和辅助函数来完成这个。

在这种情况下,我们使用namespace_test_helper,当且仅当查询的类型(或其依赖类型)来自true_type时,才会返回my_namespace

namespace support {
  template<class...Ts>
  constexpr std::false_type namespace_test_helper( Ts&&... ) { return {}; }
  template<class T>
  constexpr auto namespace_test( T&& t ) {
    return namespace_test_helper( std::forward<T>(t));
  }

}
namespace my_namespace {
  template<class T>
  constexpr std::true_type namespace_test_helper( T&& ) { return {}; }
  template<class T,
    class=std::enable_if_t<decltype(::support::namespace_test( std::declval<T>() )){}>
   >
  std::ostream& operator<<( std::ostream& os, T const& t ) {
    return os << "my <<";
  }
  enum bob {};
  void test() {
      std::cout << "hello world\n";
      std::cout << bob{} << "\n";
  }
}

int main() {
    ::my_namespace::test();
    std::cout << ::my_namespace::bob{} << "\n";
}

请注意,my_namespace内的模板参数类型也可以找到它。

我们可以将其扩展到检测哪些命名空间来自哪些;但是你必须为每个这样的命名空间定义一个不同的类型。 std::integral_constant<std::size_t, I>可以使用,但您负责为每个命名空间设置唯一的I