您会看到几种效果的组合。
-
main() 中的调用是完全合法的,因为make_unique
模板实例化与您提供给它的签名数据类型相匹配。
-
make_unique 的实现不会产生警告,因为
警告通常在系统标头中被禁用。
- Visual Studio 似乎无法检测到潜力(但不是
确定)
make_unique内部的符号转换问题。
更详细的:
1。模板实例化实际上是合法的。
std::make_unique 的典型实现如下所示(比较
cppreference):
template <typename T, typename... Args>
inline std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
在您的情况下,当您调用 std::make_unique<MyClass>(-1) 时,模板是
为一个 signed 整数实例化。因此,您不会在您的
代码,因为没有发生无符号/有符号转换。
2。系统标头通常会禁用警告。
但是,您可以正确地期待来自make_unique 的警告
执行。毕竟,当new T(...) 被您签名时
参数,有符号/无符号转换仍然发生。作为一个例子,采取
以下程序:
#include <memory>
class MyClass
{
public:
MyClass(unsigned) { }
};
template <typename T, typename... Args>
inline std::unique_ptr<T> custom_make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
int main()
{
auto uniqueP = custom_make_unique<MyClass>(-1);
(void) uniqueP;
return 0;
}
当我使用带有-Wsign-conversion 的 GCC 编译它时,我收到警告
test.cpp: 在 'std::unique_ptr<_tp> custom_make_unique(Args&& ...) [with T = MyClass; Args = {int}]':
test.cpp:17:48: 从这里需要
test.cpp:12:63:警告:从“int”转换为“unsigned int”可能会更改结果的符号 [-Wsign-conversion]
return std::unique_ptr(new T(std::forward(args)...));
所以问题是,为什么您没有收到std::make_unique() 的警告
执行?答案本质上是编译器将这些静音
其系统标头的警告。例如,<memory> 的 GCC 版本
标头包含编译指示
#pragma GCC system_header
只要这个编译指示出现在头文件中,编译器就不再
报告该标题内所有内容的警告。从
GCC documentation:
声明操作系统和运行时接口的头文件
库通常不能用严格符合的 C 语言编写。因此,GCC
对系统头文件中的代码进行特殊处理。所有警告,除了
那些由‘#warning’(见诊断)生成的,在 GCC 运行时被抑制
处理系统头文件。
另请参阅
this SO post 为
更多细节。据推测,Visual Studio 采用了类似的方法
编译器(正如您在评论中所写,标题暂时减少了
警告级别)。
3。您似乎遇到了 VisualStudio 限制。
在 VisualStudio 的情况下,还有其他一些东西在起作用。注意如何
上面的 GCC 警告说可能存在符号转换问题(取决于
关于用户将稍后输入custom_make_unique的价值观)。它出现
VisualStudio 只能在存在 确定 符号转换问题时发出警告。
请参阅以下程序:
#include <iostream>
void f(unsigned) { }
template <typename T>
void g(T val) { f(val); } // GCC issues a warning, VS does NOT
int main()
{
f(-1); // GCC and VS issue a warning
g(-1); // no conversion warning here (g<int> instantiated)
}
Try it online.