3

考虑(文件名是 hello.cpp)这段代码;这个想法是设计一个安全的数字类型转换而不会丢失或溢出。(我正在将一些代码从 MSVC 移植到 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;
}

当我通过键入使用 gcc 8.3 进行编译时,g++ -o hello hello.cpp我得到了错误error: static assertion failed: undefined integral cast

这意味着 g++ 总是在编译未使用的模板代码。

请注意,MSVC 编译了这个(这很好,因为它允许我发现我没有考虑过的任何完整的演员特化)。

显然我错过了一些东西。但是什么?

4

1 回答 1

4

GCC 并不是真正“实例化”或“编译”基本函数模板。如果是这样,您将拥有两个具有相同名称和参数列表的编译函数。正如@Raymond Chen 在评论中指出的那样,GCC 是允许但不是必需的,为没有任何有效实例化的模板引发错误。

例如:

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

不会在您给出的示例中引发错误(因为它具有有效的实例化并且未实例化)。

我怀疑 GCC 只需要将类型替换为基本模板以进行重载解析,因此它实际上只需要声明,而不是定义

您可以使用已删除的定义获得所需的行为:

template<
    typename T/*the desired type*/,
    typename/*the source type*/ Y
> T integral_cast(const Y& y) = delete;
于 2020-05-07T14:54:35.347 回答