Избегайте объяснения типа при искусственно неоднозначном вызове перегруженной функции - PullRequest
0 голосов
/ 23 сентября 2018

Минимальный пример программы:

#include <vector>
void f(std::vector<int>)    {} // #1
void f(std::vector<void *>) {} // #2
int main() { f({ 1 }); }

Было бы интуитивно понятно, что это допустимая программа: вызов с использованием перегрузки # 1 будет действительным, вызов с использованием перегрузки № 2 будет некорректнымпоэтому перегрузка № 1 должна быть выбрана.Это то, что делает clang.

К сожалению, по стандарту кажется, что это неоднозначно, потому что есть конструктор для std::vector<void *>, который можно вызвать с помощью int, неявно преобразовав его в size_t.Тот факт, что этот конструктор равен explicit, должен игнорироваться при разрешении перегрузки, если бы эта перегрузка была выбрана, программа просто не работала бы.GCC отклоняет вызов как неоднозначный, и похоже, что это правильно.

Я могу изменить код, чтобы позволить GCC принять вызов, указав имя типа: f(std::vector<int>{ 1 });.В качестве альтернативы я могу использовать диспетчеризацию тегов с параметрами по умолчанию, чтобы позволить явно указать, какую перегрузку использовать, и в то же время разрешить принимать существующие вызовы, как и раньше.

Оба из них приемлемы, но довольно быстро становятся достаточно многословными при возвращении креальный кодЕсть ли другой вариант, который позволяет мне не указывать полное имя типа, но придерживаться текущих перегрузок?На мгновение я подумал, что { 1, } может сработать, но, конечно, это не так, int i = { 1, }; также вполне допустимо, что нельзя использовать, чтобы избежать # 2.

Если это помогает исключитьВ некоторых альтернативах реальный код включает в себя std::vector<int> и std::vector<T> и включает вызов со списком инициализированных скобками, содержащим одно целое выражение, но T - это пользовательский тип, а не встроенный тип, ивыражение не является постоянным значением.

«Нет» является приемлемым ответом, но в этом случае, пожалуйста, уточните, пожалуйста, покажите, что такой опции нет.

1 Ответ

0 голосов
/ 25 сентября 2018

Всегда трудно доказать отрицание, но, учитывая возможность введения

using I=std::vector<int>;

Я думаю, вы действительно спрашиваете: «Есть ли способ избежать стандартного преобразования в size_type, чтобы удалитьдругая перегрузка из-за конфликта »?

Очевидно, что вы ничего не можете сделать с самим int, и даже после неявного преобразования в int может последовать стандартное преобразование.Но мы можем (конечно) привести SFINAE к выводу :

struct A {
  int i;
  template<class T,std::enable_if_t<std::is_same_v<T,int>>* =nullptr>
  operator T() const {return i;}
};

Затем вы можете написать

f({A{1}});

(пользовательский литерал был бы визуально более коротким, но вы сказали неконстантные выражения.)

Это зависит от вас, означает ли это да или нет для ответа, но я почти уверен, что нет другого способа использовать инициализатор скобок без разрешения стандартных преобразований.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...