Как сделать шаблон функции наименьшим приоритетом во время ADL? - PullRequest
6 голосов
/ 30 сентября 2011

У меня есть проблема, когда я хотел бы предоставить общую версию функции foo, которая может быть применена только в том случае, если для вызова не существует другого соответствия.Как я могу изменить следующий код так, чтобы last_resort::foo было хуже для derived::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 ]

2 голосов
/ 01 октября 2011

Это будет примерно так же плохо, как и получится:

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 голос
/ 30 сентября 2011

Ты ничего не можешь с этим поделать.Обе функции foo находятся в наборе перегрузки.Но ваш last_resort лучше подходит просто потому, что не требует преобразования в отличие от base :: foo для производного :: типа ().Только в случае, когда два кандидата «одинаково хороши», судя по параметрам и возможным преобразованиям, предпочтение не относится к шаблону.

0 голосов
/ 01 октября 2011

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

Этот ответ описывает, как построить решение для проверки существования функции (foo), возвращающей void.

0 голосов
/ 01 октября 2011

Вы можете предоставить перегрузку bar для типа derived::type после объявления derived::type.Это может быть namespace derived или нет.

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