Как работает поиск перегрузки функции, когда одна из функций не компилируется? - PullRequest
1 голос
/ 25 июня 2019

Так что я совсем не понимаю, как компилятор выбирает перегрузки функций. Я думал, что я понимаю, пока этот код:

#include <iostream>

using namespace std;

template<class T>
struct base_type:
    public T
{
};

template<class T>
void check(T (&)[sizeof(base_type<T>)/sizeof(base_type<T>)]) {std::cout << "yeah";}

template<class T>
void check(T) {std::cout << "nah";}

union U{};
struct S{};

int main()
{
    U u[1];
    S s[1];

    check(u); // compile error
    check(s);

    return 0;
}

Почему компилятор не выбрал 2d перегрузку check(T), когда ему не удалось проверить размер ссылки на массив при первой перегрузке?

Ответы [ 3 ]

3 голосов
/ 25 июня 2019

Только ошибки из непосредственного контекста вызывают «мягкую» ошибку, которая удаляет шаблон функции из набора перегрузки.Компилятор должен создать экземпляр base_type<T>, прежде чем он сможет оценить sizeof(base_type<T>), и любые ошибки, возникающие в результате этого создания, , а не в непосредственном контексте, и могут вызвать серьезные ошибки.

Я не уверенто, что вы действительно пытаетесь сделать, но вы, вероятно, можете сделать это, используя std::enable_if_t<std::is_union_v<T>>, чтобы отключить перегрузку.Причина, по которой это работает, заключается в том, что создание экземпляра std::enable_if, которое выполняется первым, не вызывает ошибок;результирующий класс просто не может содержать члена с именем type.Доступ к type в * непосредственном контексте .

2 голосов
/ 25 июня 2019

Также я нашел стандартную цитату, которая может сделать резервную копию ответов.

Стандартная цитата, C ++ 11 §14.8.2 / 8:

Только недопустимые типы и выражения в непосредственном контексте типа функции и ее типов параметров шаблона могут привести к сбой удержания. [Примечание: оценка замещенных типов и выражения могут привести к побочным эффектам, таким как создание специализация шаблона класса и / или шаблон функции специализации, генерация неявно определенных функций и т. д. Такие побочные эффекты не находятся в «непосредственном контексте» и могут привести к программа плохо сформирована. - конец примечания]

2 голосов
/ 25 июня 2019

SFINAE происходит при объявлении, а не в определении, и объявление base_type<U> в порядке, но выдает серьезную ошибку для его определения.

Стандарт предоставляет черты std::is_union и std::enable_if для выполнения SFINAE:

template<class T, std::enable_if_t<!std::is_union<T>::value, int> = 0>
void check(T (&)[1]) {std::cout << "yeah";}

А с C ++ 17 вы можете даже использовать if constexpr внутри функции напрямую (даже если простой if в вашем упрощенном случае подходит):

template<class T>
void check(T (&)[1])
{
    if constexpr(std::is_union<T>::value) {
        std::cout << "nah";
    } else {
        std::cout << "yeah";
    }
}
...