标准库实现是否允许具有不同于 C++ 标准的 class 定义?
Is it permissible for standard library implementation to have class definition that is different from the C++ standard?
以下代码使用 clang 和 MSVC 成功编译,但在 GCC 6.1.0 中编译失败。
#include <memory>
template<typename R, typename T, typename... Args>
T* test(R(T::*)(Args...) const)
{
return nullptr;
}
int main()
{
using T = std::shared_ptr<int>;
T* p = test(&T::get);
}
出现以下错误信息
prog.cc: In function 'int main()':
prog.cc:13:16: error: invalid conversion from 'std::__shared_ptr<int, (__gnu_cxx::_Lock_policy)2u>*' to 'T* {aka std::shared_ptr<int>*}' [-fpermissive]
T* p = test(&T::get);
~~~~^~~~~~~~~
问题是 libstdc++ 通过从基础 class std::__shared_ptr
.
继承成员函数 get
来实现 std::shared_ptr
在C++标准20.8.2.2 Class模板shared_ptr中,指定了std::shared_ptr的class定义class 以及 class.
的所有成员函数
我的问题是实施是否必须至少提供所有 public class 标准中定义的成员 class?是否允许通过从 libstdc++ 中实现的 base class 继承来提供成员函数?
标准的类型及其成员规范是规范文本,除非明确另有说明。因此,实施需要遵循......在某种程度上,实施需要遵循标准中的任何。
而这个范围就是 "as if" 规则。也就是说,只要类型的行为 "as if" 它是按指定完成的,就允许实现做它想做的事。该标准使用特定语言说明类型可以从任意的、实现提供的基础 classes 派生的原因是因为这是用户可以检测到的东西。这是可见的行为(通过隐式转换等),因此标准必须做出例外才能允许它。
继承成员 几乎 与在主 class 中声明它是一回事。实际上,我所知道的区分差异的唯一方法就是按照您在此处所做的操作:使用模板参数推导规则。即使您可以将成员指定为 Derived::get
,如果它确实来自某个基 class,编译器也会知道。
然而,[member.functions] 在这里拯救了 GCC。它具有明确的语言,允许标准库实现向 class 添加额外的重载。因此,您在此处使用 std::shared_ptr<int>::get
不是明确定义的行为。实际上,脚注 187 对此进行了澄清:
Hence, the address of a member function of a class in the C++ standard library has an unspecified type.
这只是一个脚注,但意图似乎很明确:您不能依赖任何特定的实现来 return 任何特定类型的成员指针。即使您对正确的签名应用了转换操作,也不能保证它会起作用。
因此,虽然标准库中的 class 定义是规范文本,但 [member.functions] 明确表示 只有 你可以保证的事情这些定义是您可以使用提供的参数调用这些函数。其他任何东西,比如获取成员指针,都是实现定义的。
以下代码使用 clang 和 MSVC 成功编译,但在 GCC 6.1.0 中编译失败。
#include <memory>
template<typename R, typename T, typename... Args>
T* test(R(T::*)(Args...) const)
{
return nullptr;
}
int main()
{
using T = std::shared_ptr<int>;
T* p = test(&T::get);
}
出现以下错误信息
prog.cc: In function 'int main()':
prog.cc:13:16: error: invalid conversion from 'std::__shared_ptr<int, (__gnu_cxx::_Lock_policy)2u>*' to 'T* {aka std::shared_ptr<int>*}' [-fpermissive]
T* p = test(&T::get);
~~~~^~~~~~~~~
问题是 libstdc++ 通过从基础 class std::__shared_ptr
.
get
来实现 std::shared_ptr
在C++标准20.8.2.2 Class模板shared_ptr中,指定了std::shared_ptr的class定义class 以及 class.
的所有成员函数我的问题是实施是否必须至少提供所有 public class 标准中定义的成员 class?是否允许通过从 libstdc++ 中实现的 base class 继承来提供成员函数?
标准的类型及其成员规范是规范文本,除非明确另有说明。因此,实施需要遵循......在某种程度上,实施需要遵循标准中的任何。
而这个范围就是 "as if" 规则。也就是说,只要类型的行为 "as if" 它是按指定完成的,就允许实现做它想做的事。该标准使用特定语言说明类型可以从任意的、实现提供的基础 classes 派生的原因是因为这是用户可以检测到的东西。这是可见的行为(通过隐式转换等),因此标准必须做出例外才能允许它。
继承成员 几乎 与在主 class 中声明它是一回事。实际上,我所知道的区分差异的唯一方法就是按照您在此处所做的操作:使用模板参数推导规则。即使您可以将成员指定为 Derived::get
,如果它确实来自某个基 class,编译器也会知道。
然而,[member.functions] 在这里拯救了 GCC。它具有明确的语言,允许标准库实现向 class 添加额外的重载。因此,您在此处使用 std::shared_ptr<int>::get
不是明确定义的行为。实际上,脚注 187 对此进行了澄清:
Hence, the address of a member function of a class in the C++ standard library has an unspecified type.
这只是一个脚注,但意图似乎很明确:您不能依赖任何特定的实现来 return 任何特定类型的成员指针。即使您对正确的签名应用了转换操作,也不能保证它会起作用。
因此,虽然标准库中的 class 定义是规范文本,但 [member.functions] 明确表示 只有 你可以保证的事情这些定义是您可以使用提供的参数调用这些函数。其他任何东西,比如获取成员指针,都是实现定义的。