Почему кажется, что gcc8.3 пытается скомпилировать неиспользуемую функцию шаблона? - PullRequest
3 голосов
/ 07 мая 2020

Рассмотрим (имя файла hello. cpp) этот код; идея состоит в том, чтобы разработать безопасное приведение типов numeri c без потерь или переполнения. (Я портирую код из MSV C в g ++).

#include <cstdint>
#include <iostream>

template<
    typename T/*the desired type*/,
    typename/*the source type*/ Y
> T integral_cast(const Y& y)
{
    static_assert(false, "undefined integral cast");
}

// Specialisation to convert std::uint32_t to double
template<>
inline double integral_cast(const std::uint32_t& y)
{
    double ret = static_cast<double>(y);
    return ret;
}

int main()
{
    std::uint32_t a = 20;
    double f = integral_cast<double>(a); // uses the specialisation
    std::cout << f;
}

Когда я компилирую с g cc 8.3, набрав g++ -o hello hello.cpp, я получаю сообщение об ошибке error: static assertion failed: undefined integral cast.

Это означает, что g ++ всегда компилирует неиспользуемый код шаблона.

Обратите внимание, что MSV C компилирует это (что приятно, поскольку позволяет мне определять любые специализации интегрального приведения, которые я не рассматривал) .

Ясно что-то не хватает. Но что?

1 Ответ

4 голосов
/ 07 мая 2020

G CC на самом деле не «создает» или «компилирует» шаблон базовой функции. Если бы это было так, у вас были бы две скомпилированные функции с одинаковым именем и списком параметров. Как отметил @Raymond Chen в комментариях, G CC разрешено, но не обязательно, чтобы вызывать ошибку для шаблонов, которые не имеют действительного экземпляра.

Например:

template<
    typename T/*the desired type*/,
    typename/*the source type*/ Y
> T integral_cast(const Y& y)
{
        static_assert(sizeof(Y) == 1);
};

Не вызовет ошибки в приведенном вами примере (потому что он имеет действующий экземпляр и не создается).

Я подозреваю, что G CC просто нужно заменить типы в базовый шаблон для разрешения перегрузки, поэтому на самом деле ему просто нужно объявление , а не определение .

Вы можете получить желаемое поведение, используя удаленное определение:

template<
    typename T/*the desired type*/,
    typename/*the source type*/ Y
> T integral_cast(const Y& y) = delete;
...