Удаление неиспользованной перегрузки вызывает ошибку компиляции?

Я пытался удалить некоторые неиспользуемые перегрузки и вызвал ошибку компиляции, которая, как сказал компилятор, была ошибкой замены шаблона. Но я подумал: «Сбой замещения — это не ошибка», и вообще, зачем устранять перегрузку?

Простые начинания:

#include <string>

int ParseInt(const char *);
int ParseInt(std::string);

bool F(int(*)(const char *));

bool User() {
return F(ParseInt);
}

Здесь User () вызывает F с адресом процедуры синтаксического анализа. Все хорошо. ParseInt перегружен, но только одна перегрузка соответствует подписи F.

Введите шаблонную перегрузку F:

bool F(int(*)(const char *));

template <typename T>
struct MetaDeduce {
typedef typename T::X type;
};

template <typename T>
typename MetaDeduce<T>::type F(const T&);

Теперь есть странная перегрузка шаблона F, но это нормально, потому что указатели на функции в любом случае не имеют членов с именем X. Все компилируется, все хорошо.

ДО ТЕХ ПОР….

#include <string>

int ParseInt(const char *);
// int ParseInt(std::string);  // commenting this out caused a compiler error!

bool F(int(*)(const char *));

template <typename T>
struct MetaDeduce {
typedef typename T::X type;
};

template <typename T>
typename MetaDeduce<T>::type F(const T&);

bool User() {
return F(ParseInt);
}

Как видно на Годболт ( http://goo.gl/2Yd04p ), это приводит к странной ошибке компиляции:

10 : error: type 'int (const char *)' cannot be used prior to '::'
because it has no members
typedef typename T::X type;
^
14 : note: in instantiation of template class 'MetaDeduce<int (const char *)>'
requested here
typename MetaDeduce<T>::type F(const T&);
^

WTF ??? Похоже, что компилятор жалуется на ошибку замещения, но почему раньше это не было проблемой? И вообще, я думал, что ошибка замены не была ошибкой! В чем дело?

4

Решение

Это вызвано тонким взаимодействием между двумя языковыми свойствами

  1. SFINAE применяется только в непосредственный контекст. Ваш MetaDeduce<T> не определяется в таком непосредственном контексте, и это делает typename MetaDeduce<T>::type серьезная ошибка. Но SFINAE относится к typename T::Xи использование этого скомпилирует ваш код даже с ParseInt(std::string) перегрузка закомментирована.

    template <typename T>
    typename T::X F(const T&);
    

Живой пример (обратите внимание, что вы получаете ошибки компоновщика, потому что вы не определили свои функции)

  1. Так что если typename MetaDeduct<T>::type виновник, почему он работал с двумя перегрузками ParseInt? Хорошо, рассмотрим, что произойдет, если у вас будет только шаблон F и оба ParseInts. И для удобства, дайте этот шаблон F тип возврата bool для игнорирования на данный момент ошибки замещения.

    int ParseInt(const char *);
    int ParseInt(std::string);
    
    template <typename T>
    bool F(T const&);
    
    bool User() { return F(ParseInt); } // error, cannot deduce template argument
    

Живой пример

С двумя перегрузками ParseInt и никакой дополнительной информации в звонке F(ParseInt), компилятор не может определить, какая версия ParseInt должен соответствовать параметру шаблона T, В контексте этого фрагмента это приведет к серьезной ошибке (потому что у вас будет пустой набор перегрузки), но с дополнительной перегрузкой без шаблона F(int(*)(const char*)) это не будет (потому что ParseInt(const char*) будет соответствовать этому). Обратите внимание, что, поскольку вывод аргументов не удается здесь, подстановка аргумента даже не будет иметь место в случае, если тип возвращаемого значения был typename MetaDeduce<T>::Type,

По сути, две перегрузки ParseInt защитил вас от неудачи замещения в не непосредственном контексте. Как только вы убираете один из них, вывод аргумента завершается успешно, и не немедленная замена подстановки приводит к серьезной ошибке.

Это немного похоже на пересечение улицы с красным светом и спасение, потому что два встречных грузовика сталкиваются друг с другом, прежде чем они могут ударить вас. Только с одним грузовиком тебя бьют.

4

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]