6

У меня проблема, когда создание указателя функции для перегруженной функции приводит к ошибке компиляции g ++ 4.7 и g ++ 4.8, но не по g ++ 4.4, g ++ 4.6 или clang ++ 3.2 (и, возможно, VS2010).Преобразование перегруженной функции неоднозначно

Немного разобравшись, выясните, есть ли проблема с g ++ или с моим кодом, я все еще не могу решить. Являются ли правила разрешения перегрузки применимыми к преобразованию указателя функции, отличного от тех, которые применяются к вызовам функций?

Это несколько минимизировано код, который демонстрирует проблему:

template < class T > 
struct Dummy { 
    typedef T value_type; 
    value_type value; 
}; 

template < class T > 
typename T::value_type f (const T& x) { 
    return x.value; 
} 

template < class T > 
T f (Dummy<T> const& x) { 
    return x.value + 1; 
} 

int main (int, char**) { 
    Dummy<int> d = { 1 }; 
    // No ambiguity here 
    d.value = f(d); 
    // This is ambiguous for *some* compilers 
    int (* const f_ptr)(Dummy<int> const&) = f; 
    return f_ptr(d); 
} 

лязг ++ 3.2, G ++ 4.4 и 4.6 г ++ скомпилировать это с -Wall -pedantic --std=c++98 без предупреждений.

г ++ 4.7 и г ++ 4.8, однако дать следующее сообщение об ошибке:

test.cc: In function ‘int main(int, char**)’: 
test.cc:15:45: error: converting overloaded function ‘f’ to type ‘int (* const)(const struct Dummy<int>&)’ is ambiguous 
test.cc:6:18: error: candidates are: typename T::Type f(const T&) [with T = Dummy<int>; typename T::Type = int] 
test.cc:9:3: error:     T f(const Dummy<T>&) [with T = int] 

Является ли это проблема с новыми версиями г ++ или мой код на самом деле так?

Если да, то как бы решить эту двусмысленность?

+1

Вот является вещь, чтобы попытаться: закомментировать один f(), скомпилировать файл. Прокомментируйте другой файл f(), скомпилируйте файл. Результат, который вы получите, должен прояснить эту ситуацию совсем немного. – Arkadiy

+0

@ Аркадий, вы утверждаете, что это признак того, что результат должен быть двусмысленностью? –

+0

Если исходный компилятор с какой-либо из функций закомментировал, то я бы сказал, что есть в leas сильная возможность, что они неоднозначны. Если какая-либо из функций удовлетворяет требованию, мы должны будем отдать предпочтение одному из них, чтобы избежать двусмысленности, и никакое предпочтение не предполагает себя, по крайней мере, при первом показе. – Arkadiy

ответ

3

Это проблема с новыми версиями g ++ или мой код на самом деле не так?

Я предполагаю, что это юридический кодекс (но я не уверен). Чтобы добавить в список: он компилируется с clang 3.3 и icc 13.1.3.

Как можно решить такую ​​двусмысленность?

Вы можете использовать

int (* const f_ptr)(Dummy<int> const&) = f<int>; 

выбрать вторую перегрузку или

int (* const f_ptr)(Dummy<int> const&) = f<Dummy<int> >; 

, чтобы выбрать первый.

Если вы не хотите вручную устранять неоднозначность (например, мое предложение выше), я могу предложить обходное решение, которое использует SFINAE для устранения неоднозначности. Я предполагаю, что вы можете использовать C++ 11 (аргументы шаблона по умолчанию для шаблонов функций), но я считаю, что с некоторой дополнительной работой он может быть расширен до C++ 98.

Изменение определения f к:

template < class T, class R = typename T::value_type> 
R f (const T&) { 
    return x.value; 
} 

template < class T, class R = T> 
R f (Dummy<T> const&) { 
    return x.value + 1; 
} 

При этом, исходная линия (ниже) отлично компилируется в GCC (4.7.3 и 4.8.1):

int (* const f_ptr)(Dummy<int> const&) = f; 
+0

Это сделало трюк. Спасибо. – user2961413

Смежные вопросы