如何在ADL期间使功能模板成为最低优先级?

时间:2011-09-30 18:37:39

标签: c++ templates argument-dependent-lookup

我有一个问题,我想提供一个函数foo的泛型版本,只有在调用绝对没有其他匹配时才能应用。如何修改以下代码,使last_resort::fooderived::type的匹配程度低于base::foo?我想找到一个解决方案,它不涉及修改bar的定义,而是保留last_resort::foo的参数类型。

#include <iostream>

namespace last_resort
{

template<typename T> void foo(T)
{
  std::cout << "last_resort::foo" << std::endl;
}

}

template<typename T> void bar(T)
{
  using last_resort::foo;
  foo(T());
}

namespace unrelated
{

struct type {};

}

namespace base
{

struct type {};

void foo(type)
{
  std::cout << "base::foo" << std::endl;
}

}

namespace derived
{

struct type : base::type {};

}

int main()
{
  bar(unrelated::type()); // calls last_resort::foo
  bar(base::type());      // calls base::foo
  bar(derived::type());   // should call base::foo, but calls last_resort::foo instead

  return 0;
}

4 个答案:

答案 0 :(得分:2)

这就差不多了:

struct badParam { template <typename T> badParam(T t) { } };
namespace last_resort {
  void foo(badParam, int dummy = 0, ...) {
    std::cout << "last_resort::foo" << std::endl;
  }
}

您有一个用户定义的转换,一个默认参数和一个未使用的省略号。

[编辑]

轻微变体,要保存T我将用户定义的转换移动到虚拟参数:

struct badParam { 
    badParam() { }
    operator int() { return 42; }
};
namespace last_resort {
  template <typename T> void foo(T t, int dummy = badParam(), ...) {
    std::cout << "last_resort::foo" << std::endl;
  }
}

答案 1 :(得分:1)

你无能为力。两个foo函数都在重载集中。但是你的last_resort是一个更好的匹配,因为它不需要像gen :: type()的base :: foo那样的转换。只有在两个候选人根据参数和可能的转换判断“同样好”的情况下,才会使用非模板。

答案 2 :(得分:0)

在声明bar后,您可以为derived::type类型提供derived::type的重载。这可以是namespace derived或不是。

void bar(derived::type)
{
  foo(derived::type());
}

答案 3 :(得分:0)

可以使用last_resort::foo从重载集中删除

disable_if。如果last_resort::foo(T)格式正确,我们的想法是禁用foo(T)。这会导致last_resort::foo(T)成为foo的最差匹配:

namespace test
{

template<typename T> struct has_foo { ... };

}

namespace last_resort
{

template<typename T>
  struct disable_if_has_foo
    : std::enable_if<
        !test::has_foo<T>::value
      >
{};

template<typename T>
  typename disable_if_has_foo<T>::type foo(T)
{
  std::cout << "last_resort::foo" << std::endl;
}

}

输出:

$ g++ last_resort.cpp 
$ ./a.out 
last_resort::foo
base::foo
base::foo

This answer描述了如何构建解决方案,以检查是否存在返回foo的函数(void)。