C ++ 17是2017年批准的C ++标准的名称。它基于以前的C ++ 14标准,改进了核心语言和标准库,并添加了一些新的语言功能。
将 NULL 与 nullptr 传递给模板参数有什么区别?
我正在处理一个相当统一的供应商提供的 API,并且也希望以统一的方式检查并处理任何故障。为此,我编写了以下包装: 模板 我正在处理一个相当统一的供应商提供的 API,并且也希望以统一的方式检查和处理任何故障。为此,我编写了以下包装: template <typename Func, typename... Args> auto awrap(Func &func, Args&&... args) { auto code = func(args...); if (code >= 0) return code; ... handle the error ... }; ... awrap(handlepath, handle, path, NULL, 0, coll, NULL); 上面的代码用 clang 编译得很好,但是 g++13 —— 和 Microsoft VC++ —— 都抱怨两个 NULL 参数: ... error: invalid conversion from 'int' to 'const char*' [-fpermissive] 87 | auto code = func(args... 用 NULL 替换两个 nullptr 可以解决问题,但为什么这很重要? 很可能,预处理器将 NULL 变成 0x0 甚至 0 ,但最初的调用从未引起“注意”。使用 NULL 非常适合: handlepath(handle, path, NULL, 0, coll, NULL); 当在包装器中使用时,为什么它(对于某些编译器)是一个问题? 更新:我的 FreeBSD 系统上的 /usr/include/sys/_null.h 有以下代码: #ifndef NULL #if !defined(__cplusplus) #define NULL ((void *)0) #else #if __cplusplus >= 201103L #define NULL nullptr #elif defined(__GNUG__) && defined(__GNUC__) && __GNUC__ >= 4 #define NULL __null #else #if defined(__LP64__) #define NULL (0L) #else #define NULL 0 #endif /* __LP64__ */ #endif /* __GNUG__ */ #endif /* !__cplusplus */ #endif 所以: 对于 C,NULL 是 (void *)0; 对于 clang++ 来说 NULL 和 nullptr 是同一件事,而对于 GNU 来说可能不是...... 在许多实现中,NULL只是#define,表示整数文字0,例如: #define NULL 0 您可以直接将 literal 0 分配给任何指针,这就是为什么将 NULL 直接传递给目标函数效果很好。 由于您将 NULL 传递给模板参数,因此该参数将被推导为类型 int,如错误消息所示。 要将 int 变量分配给指针,您需要显式类型转换。 而nullptr是nullptr_t类型,也可以直接赋值给任何指针。 nullptr_t 只有 1 个可能的值。因此,当将 nullptr 传递给模板参数时,该参数将被推导为类型 nullptr_t。并且编译器知道如何将 nullptr_t 分配给指针。 因此,在调用模板时,您应该使用nullptr,但是如果您想使用NULL,那么您必须将其类型转换为(char*)NULL(或等效项),或者参数的任何其他指针类型期待。 NULL 是一个宏,可以定义为 nullptr 或零值整数文字(例如 0 或 0L)。哪一个是实现定义的,但因为只有后一种选择在 C 和 C++11 之前版本中有效,所以看到后者的机会很大。 nullptr 是 nullptr_t 的对象。这种类型的任何表达式始终是所谓的“空指针常量”,这意味着它可以隐式转换为任何指针类型的空指针值。 然而,零值整数表达式并不总是空指针常量。具体来说,only空值整数literals是可以转换为指针类型的空指针常量。 因此,如果将 0 直接传递给期望 char* 运行良好的函数,则文字 0 是一个空指针常量,可以隐式转换为指针类型,从而产生空指针值. 但是您将文字作为整数类型传递给 awrap(通过推导)。当您在 func(args...) 中使用参数时,它仍然是一个值为零的整数表达式,但它不是一个 整数文字。因此,参数不是空指针常量,并且不能隐式转换为char*。 因此,您无法通过包装器传递指针参数 0,因为您必须准确命名应该应用转换的文字。是否可以使用 NULL 是由实现定义的。如果 NULL 恰好被定义为 nullptr,则它有效,但如果它是零值整数文字,则无效。 这是一个很好的例子,说明为什么只应该使用 nullptr。零值整数文字的隐式转换行为仅因从 C 继承的历史原因而存在。如果该语言是今天设计的,我怀疑有人会在转换中添加如此奇怪的特殊情况。通常,可能的转换由表达式的类型和值类别确定。这是值和语法结构影响转换行为的唯一特殊情况。
将 NULL 与 nullptr 传递给模板参数时有什么区别?
我正在处理一个相当统一的供应商提供的 API,并且也希望以统一的方式检查并处理任何故障。为此,我编写了以下包装: 模板 我正在处理一个相当统一的供应商提供的 API,并且也希望以统一的方式检查和处理任何故障。为此,我编写了以下包装: template <typename Func, typename... Args> auto awrap(Func &func, Args&&... args) { auto code = func(args...); if (code >= 0) return code; ... handle the error ... }; ... awrap(handlepath, handle, path, NULL, 0, coll, NULL); 上面的代码用 clang 编译得很好,但是 g++13 —— 和 Microsoft VC++ —— 都抱怨两个 NULL 参数: ... error: invalid conversion from 'int' to 'const char*' [-fpermissive] 87 | auto code = func(args... 用 NULL 替换两个 nullptr 可以解决问题,但为什么这很重要? 很可能,预处理器将 NULL 变成 0x0 甚至 0 ,但最初的调用从未引起“注意”。使用 NULL 非常适合: handlepath(handle, path, NULL, 0, coll, NULL); 当在包装器中使用时,为什么它(对于某些编译器)是一个问题? 在许多实现中,NULL只是#define,表示整数文字0,例如: #define NULL 0 您可以直接将 literal 0 分配给任何指针,这就是为什么将 NULL 直接传递给目标函数效果很好。 由于您将 NULL 传递给模板参数,因此它被推导为类型 int,如错误消息所述。 要将任何 int(有或没有 0 值)分配给任何指针,您需要显式地对其进行类型转换。 而nullptr是nullptr_t类型,它也可以分配给任何指针。 nullptr_t 只有 1 个可能的值。因此,将 nullptr 传递给模板参数会将其推断为 nullptr_t,并且编译器知道如何将 nullptr_t 分配给指针。 因此,在调用模板时,您应该使用nullptr,但是如果您想使用NULL,那么您必须将其类型转换为(char*)NULL(又名reinterpret_cast<char*>(0)),或者任何其他指针类型参数正在等待。 NULL 是一个宏,可以定义为 nullptr 或零值整数文字(例如 0 或 0L)。哪一个是实现定义的,但因为只有后一种选择在 C 和 C++11 之前版本中有效,所以看到后者的机会很大。 nullptr 是 nullptr_t 的对象。这种类型的任何表达式始终是所谓的“空指针常量”,这意味着它可以隐式转换为任何指针类型的空指针值。 然而,零值整数表达式并不总是空指针常量。具体来说,only空值整数literals是可以转换为指针类型的空指针常量。 因此,如果将 0 直接传递给期望 char* 运行良好的函数,则文字 0 是一个空指针常量,可以隐式转换为指针类型,从而产生空指针值. 但是您将文字作为整数类型传递给 awrap(通过推导)。当您在 func(args...) 中使用参数时,它仍然是一个值为零的整数表达式,但它不是一个 整数文字。因此,参数不是空指针常量,并且不能隐式转换为char*。 因此,您无法通过包装器传递指针参数 0,因为您必须准确命名应该应用转换的文字。是否可以使用 NULL 是由实现定义的。如果 NULL 恰好被定义为 nullptr,则它有效,但如果它是零值整数文字,则无效。 这是一个很好的例子,说明为什么只应该使用 nullptr。零值整数文字的隐式转换行为仅因从 C 继承的历史原因而存在。如果该语言是今天设计的,我怀疑有人会在转换中添加如此奇怪的特殊情况。通常,可能的转换由表达式的类型和值类别确定。这是值和语法结构影响转换行为的唯一特殊情况。
我正在处理一个相当统一的供应商提供的 API,并且也希望以统一的方式检查并处理任何故障。为此,我编写了以下包装: 模板<
如何使用std::stringstream将自定义结构体转换为std::string?
我想将自定义结构体转换为std::string,我想到使用std::stringstream,因为它可以轻松地将各种类型转换为std::string。 模板 我想将一个自定义的结构体转换为std::string,我想到使用std::stringstream,因为它可以轻松地将各种类型转换为std::string。 template<typename T> std::string type_to_string(const T &in) { std::stringstream ss; ss << in; return ss.str(); } struct st_Key { std::string a; int b; char c; ... template<typename OStream> friend OStream &operator<<(OStream &os, const st_Key &c) { // wanted form to output return os << "a" << "=[" << c.a<< "]" << "b" << "=[" << c.b<< "]" << "c" << "=[" << c.c<< "]"; } }; 我想如何转换为 std::string std::string s = type_to_string(st_Key{"a", 1, 'c'}); 但是编译时出现一些错误: <source>: In instantiation of 'OStream& operator<<(OStream&, const st_Key&) [with OStream = std::__cxx11::basic_stringstream<char>]': <source>:14:8: required from 'std::string type_to_string(const T&) [with T = st_Key; std::string = std::__cxx11::basic_string<char>]' <source>:36:35: required from here <source>:31:36: error: invalid initialization of reference of type 'std::__cxx11::basic_stringstream<char>&' from expression of type 'std::basic_ostream<char>' 31 | << "=[" << c.c<< "]"; | ^~~ 那么这有什么问题呢? https://godbolt.org/z/q6zo8r98s 标准库中包含的所有 operator<< 函数不能直接与特定的流类型一起使用。相反,他们采用 std::basic_ostream<CharT, Traits>& 作为参数,并将其用作返回类型。 在您的 operator<<(OStream&, const st_Key&) 中,您尝试返回 std::stringstream&,但 return 语句中使用的输出运算符仅返回基类。将基类引用强制转换回派生类型不是隐式的。 您可以执行与 std 函数相同的操作,并使用 basic_ostream 作为类型,而不是特定流类型的模板: template<typename CharT, typename Traits> friend std::basic_ostream<CharT, Traits> &operator<<(std::basic_ostream<CharT, Traits> &os, const st_Key &c) { // wanted form to output return os << "a" << "=[" << c.a<< "]" << "b" << "=[" << c.b<< "]" << "c" << "=[" << c.c<< "]"; }
我正在处理一个供应商提供的 C 库(我们称之为 foo),它提供了大量的 API 调用。所有这些函数都采用(预初始化的)句柄(FOOHandle 类型)并在 su 上返回 0...
为了更好地理解这个问题,下面是代码: // 代码1 #包括 #包括 结构 tls_test { tls_测试() { std::cout << "tls_test ...
如何返回无框窗口中边框的调整大小逻辑? 框架窗口具有以下逻辑: QML 中的代码: 导入QtQuick 导入 QtQuick.Controls 2.5 导入 Qt5Compat.GraphicalEffects 导入NR...
如何导出cpp文件中定义的SFINAE约束的ctor以用于显式实例化的模板类?
这是我的尝试: 定义 Foo 模板类并声明但不定义仅针对 NTTP N 给定值的 ctor 的标头, // foo.hpp #包括 模板 这是我的尝试: 定义 Foo 模板类的标头,并仅针对 NTTP N 的给定值声明但不定义 ctor, // foo.hpp #include <type_traits> template<int N> struct Foo { template<int M = N, std::enable_if_t<M == 2, int> = 0> Foo(int); }; 定义该 ctor 的 cpp 文件并显式实例化 Foo 以获得对应于未 SFINAEd 的 ctor 的值, // foo.cpp #include "foo.hpp" template<int N> template<int M, std::enable_if_t<M == 2, int>> Foo<N>::Foo(int) {} template struct Foo<2>; 主要 TU,实例化 Foo<2> 类的对象, // main.hpp #include "foo.hpp" int main() { Foo<2>{0}; } 如果我尝试编译上面的两个 TU 并链接它们,我会从链接器中收到以下错误: main.cpp:(.text+0x24): undefined reference to `Foo<2>::Foo<2, 0>(int)' collect2: error: ld returned 1 exit status 确实,我没有看到任何来自foo.cpp的符号,因为这个 nm foo.o 没有输出。 如果我添加另一个不受约束的 ctor,例如 // foo.hpp // … struct Foo { Foo(int, int); // … 和 // foo.cpp // … template<int N> Foo<N>::Foo(int, int) {} // … 然后我确实得到了我所期望的: nm foo.o | c++filt 0000000000000000 W Foo<2>::Foo(int, int) 0000000000000000 W Foo<2>::Foo(int, int) 0000000000000000 n Foo<2>::Foo(int, int) 显式实例化模板类不会实例化模板成员函数。 您也需要显式实例化这些方法: template Foo<2>::Foo<2, 0>(int); 演示
我有一个带有重载方法的类: #包括 #包括 结构重载 { 无效 foo() { std::cout << "foo" << std::endl; } ...
模板 结构获取; 模板 结构获取> { static_assert(std::false_type::value, "向量索引超出范围!"); };
当前调用一个复杂的“计算器”,如下所示: 结果=计算器.calc(a, b, 额外); 不幸的是,它有时可能会由于服务器上发生不相关的更改而失败...
以下代码将无法构建,任何有关原因的反馈将不胜感激。 void bar(std::string str, int& a, int& b) { } 模板 无效 foo(std::fu...
我试图使用新的 c++17 属性 [[maybe_unused]] 忽略未使用的参数警告,如下所示。 int main([[maybe_unused]] int argc, char** argv) { //... } 但我仍然收到警告:
将`std::numeric_limits`专门化为`std::byte`是否安全?
令我惊讶的是 std::numeric_limits::digits 返回 0,而我期待的是 8。我相信这是由于缺乏 std::byte 的专业化,因此默认为,好吧,def...
《C++ Concurrency in Action》一书中的无锁队列实现中的这个“for”循环是什么意思?
我正在阅读 Anthony Williams 的《C++ Concurrency in Action, Second Edition》,我遇到了这段代码: 模板 类lock_free_queue { 私人的: 无效 set_new_tail(
用 std::string_view 替换所有 const std::string & 是一个不错的选择吗?
我对内存分配和复制非常敏感。因此,如果函数需要 std::string 对象作为输入,我总是使用 const std::string &。 最近,我发现 const std::string & will con...
用 std::string_view 替换所有 const std::string & 是一个不错的选择吗?
我对内存分配和复制非常敏感,因此,如果函数需要 std::string 对象作为输入,我总是使用 const std::string &。 最近,我发现了 const std::string & will
有没有办法找到我的代码中所有出现的 std::vector<bool> ?
我管理一个包含很多模板类的大型复杂代码。 我想禁止在代码中使用 std::vector (因为这是编译问题的一个反复出现且痛苦的原因......
将 `std::string` 临时值传递给 `std::string_view` 参数是否安全?
假设我有以下代码: void some_function(std::string_view 视图) { std::cout << view << '\n'; } int main() { some_function(std::string{"hello, world"}); /...