我试图在命名空间中调用重载函数,并且有点挣扎。

工作示例1:无 namespace

class C {};

inline void overloaded(int) {}

template<typename T> void try_it(T value) {
  overloaded(value);
}

inline void overloaded(C) {}


int main()
{
  try_it(1);
  C c;
  try_it(c);
  return 0;
}

工作示例2:在模板之前定义的所有重载
class C {};

namespace n {
  inline void overloaded(int) {}
  inline void overloaded(C) {}
}

template<typename T> void try_it(T value) {
  n::overloaded(value);
}

int main()
{
  try_it(1);
  C c;
  try_it(c);
  return 0;
}

损坏的示例3:模板之后出现一些重载
class C {};

namespace n {
  inline void overloaded(int) {}
}

template<typename T> void try_it(T value) {
  n::overloaded(value);
}

namespace n {
  inline void overloaded(C) {}
}

int main()
{
  try_it(1);
  C c;
  try_it(c); // /tmp/test.cpp: In function ‘void try_it(T) [with T = C]’:
             // /tmp/test.cpp:19:15:   instantiated from here
             // /tmp/test.cpp:8:7: error: cannot convert ‘C’ to ‘int’ for argument ‘1’ to ‘void n::overloaded(int)’

  return 0;
}

为什么会这样呢?为了能够在模板函数之后声明或定义重载,我需要做什么?

最佳答案

这是从属名称查找的问题。

overloaded(value);表达式中,名称overloaded是根据[temp.dep]/1依赖的。

据我所知,在表达式n::overloaded(value)中,名称overloaded(在id表达式n::overloaded中)是,而不是依赖。

从属名称查找非常特殊,[temp.dep.res]/1



(在文件末尾有一个函数模板的实例化点,因此可以找到来自关联 namespace 的所有声明。)

对于非从属名称,将应用常规查找规则(从定义上下文中查找)。

因此,要查找在模板定义之后声明的名称,它们必须是依赖的,并可以通过ADL查找。

一个简单的解决方法是将另一个参数引入函数overloaded或包装该参数,以使该函数的一个参数具有关联的命名空间n:

#include <iostream>

class C {};

namespace n {
  struct ADL_helper {};
  inline void overloaded(int, ADL_helper = {})
  { std::cout << "n::overloaded(int,..)" << std::endl; }
}

template<typename T> void try_it(T value) {
  overloaded(value, n::ADL_helper{});
}

namespace n {
  inline void overloaded(C, ADL_helper = {})
  { std::cout << "n::overloaded(C,..)" << std::endl; }
}

int main()
{
  try_it(1);
  C c;
  try_it(c);
}

或者:
namespace n {
  template < typename T >
  struct wrapper { T elem; };

  inline void overloaded(wrapper<int>)
  { std::cout << "n::overloaded(wrapper<int>)" << std::endl; }
}

template<typename T> void try_it(T value) {
  overloaded(n::wrapper<T>{value});
}

namespace n {
  inline void overloaded(wrapper<C>)
  { std::cout << "n::overloaded(wrapper<C>)" << std::endl; }
}

10-07 17:02