Примените директиву 'using std:: foo' в список инициализатора конструктора локально (С++)
В соответствии с пользовательским типом, следующий фрагмент показывает общий подход, позволяющий функции автоматически выбирать предоставленную пользователем перегрузку, специфичную для этого типа, или общую реализацию функции из стандартной библиотеки, если нет.
// assume std::foo is a real function template returning an int
namespace a {
struct b { };
int foo(b& ab) { ... }
}
int bar(a::b& ab)
{
using std::foo;
return foo(ab);
}
Этот подход автоматически выбирает a::foo
вместо std::foo
, если он существует.
Мой вопрос: возможно ли добиться аналогичного поведения, когда рассматриваемый вызов является частью списка инициализаторов конструктора?
struct bar2
{
bar2(a::b& ab);
int i;
};
bar2::bar2(a::b& ab)
: i{foo(ab)} // want a::foo if available, else std::foo
{ }
Очевидно, что положить тело using std::foo
в тело конструктора слишком поздно. Однако, если я поставил его перед определением конструктора, я введу std::foo
в глобальное пространство имен, которое также нежелательно.
Есть ли способ получить лучшее из обоих миров в этой ситуации?
Ответы
Ответ 1
В соответствии с Может ли оператор using появиться в списке инициализации конструктора? одна работа заключается в использовании частной статической функции, например:
struct bar2
{
bar2(a::b& ab);
int i;
private:
static int wrapper(a::b& f)
{
using std::foo;
return foo(f);
}
};
bar2::bar2(a::b& ab)
: i{wrapper(ab)} // want a::foo if available, else std::foo
{ }
В этом случае вы можете сохранить преимущества списка инициализации без необходимости переместить инициализацию в тело конструктора. OP в связанном выше вопросе утверждает, что он не предоставляет ADL, но работает для меня. Чтобы проверить, просто удалите:
int bar(foo f)
{
std::cout << "custom.\n";
return 0;
}