Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 确定是否::标准::数值限制<;T>;实例化是安全的_C++_Templates_C++11_C++03 - Fatal编程技术网

C++ 确定是否::标准::数值限制<;T>;实例化是安全的

C++ 确定是否::标准::数值限制<;T>;实例化是安全的,c++,templates,c++11,c++03,C++,Templates,C++11,C++03,类模板::std::numeric_limits只能为类型T实例化,它可以是函数的返回值,因为它总是定义成员函数,如static constepr T min()noexcept{return T();}(有关c++03或c++11中的非专门版本的更多信息,请参阅) 如果T为,即int[2]实例化将立即导致编译时错误,因为int[2]不能作为函数的返回值 使用安全版本包装::std::numeric_limits很容易-如果已知确定实例化::std::numeric_limits是否安全的方法。

类模板
::std::numeric_limits
只能为类型
T
实例化,它可以是函数的返回值,因为它总是定义成员函数,如
static constepr T min()noexcept{return T();}
(有关c++03或c++11中的非专门版本的更多信息,请参阅)

如果
T
为,即
int[2]
实例化将立即导致编译时错误,因为
int[2]
不能作为函数的返回值

使用安全版本包装
::std::numeric_limits
很容易-如果已知确定实例化
::std::numeric_limits
是否安全的方法。这是必要的,因为如果可能,应该可以访问有问题的函数

测试
::std::numeric_limits::is_specialized
的明显(也是明显错误的)方法不起作用,因为它需要实例化有问题的类模板


有没有一种方法可以测试实例化的安全性,最好不要枚举所有已知的坏类型?甚至可能是一种确定任何类模板实例化是否安全的通用技术?

关于决定是否可以为函数返回类型的类型特征,我将这样做:

#include <type_traits>

template<typename T, typename = void>
struct can_be_returned_from_function : std::false_type { };

template<typename T>
struct can_be_returned_from_function<T,
    typename std::enable_if<!std::is_abstract<T>::value,
    decltype(std::declval<T()>(), (void)0)>::type>
    : std::true_type { };
#包括
模板
结构可以从函数返回:std::false\u type{};
模板
结构可以从函数()返回,(void)0)>::type>
:std::true_type{};
另一方面,您可能希望使用标准类型特征来确定是否可以为特定类型专门化
numeric\u limits

根据C++11标准第18.3.2.1/2段中关于<代码>数值限制类模板的规定,事实上:

应为每种算术类型提供专门化,包括浮点和整数,包括
bool
。 成员
是专门化的
应适用于
数值限制的所有此类专门化

C++11解决方案 由于
T
仅作为静态成员函数的返回类型出现在非专用
::std::numeric_limits
的声明中(请参见C++03 18.2.1.1和C++11 18.3.2.3),因此此特定问题足以确保这样做是声明安全的

这导致编译时错误的原因是,使用模板参数可能不会在模板专门化的实例化中导致格式错误的构造(C++03 14.3/6,C++11 14.3/6)

对于启用C++11的项目,Andy Prowl的
可以从函数返回
解决方案在所有相关情况下都有效:,但它不容易移植到C++03环境。当使用不完整的类型()实例化时,会在中导致错误。建议的解决方案将接受不完整的类,而不是导致错误。当前的Microsoft编译器(msvc 1700/VS2012)似乎不喜欢此解决方案,无法编译

Jonathan Wakely提出了一个解决方案,该方案利用
std::is_convertible
来确定
T
是否可以作为函数的返回值。这也消除了不完整的类,并且很容易显示正确的类(它在C++11中定义为完全按照我们的要求执行)。执行表明,所有已知有问题的情况(数组、未定义长度的数组、函数、抽象类)都能正确识别。另外,它还可以正确识别不完整的类,这些类是标准不允许作为
数值限制的参数的(见下文),尽管它们在实践中似乎不会引起问题,只要实际没有调用有问题的函数。测试执行:。某些当前编译器(icc 1310和msvc 1700,VS2012的编译器)使用此方法生成不正确的结果

Tom Knapen的
is_算术
解决方案是一个非常简洁的C++11解决方案,但需要专门从事
数值限制
的实现者也专门从事
is_算术
。或者,在其基本情况下继承自
is_算术
(该类型可能被称为
数值_限制_是专门的
)的类型可能在这些情况下专门化,因为专门化
是抽象的
在语义上可能不正确(例如,未指定所有基本算术运算符,但仍然是有效的类整数类型的类型)。
这种白名单方法确保即使是不完整的类型也能得到正确的处理,除非有人恶意地试图强制编译错误

警告 从混合结果可以看出,即使使用当前的编译器,C++11的支持仍然参差不齐,因此您使用这些解决方案的里程可能会有所不同。C++03解决方案将受益于更一致的结果以及在不希望切换到C++11的项目中使用的能力

面向健壮的C++03解决方案 第C++11 8.3.5/8段列出了返回值的限制:

如果参数类型包括“指向T的未知边界数组的指针”或“引用T的未知边界数组”形式的类型,程序格式不正确。函数不应具有返回类型的数组或函数,尽管它们可能具有返回类型的指针或对此类对象的引用。不应具有函数数组,尽管可以具有指向函数的指针数组

并在第C++11 8.3.5/9段中继续说明:

类型不得在返回或参数类型中定义。参数类型或函数定义的返回类型不得为不完整的类类型(可能为cv限定),除非函数定义嵌套在该类的成员规范中
(包括类内定义的嵌套类中的定义)

这与第C++03 8.3.5/6段基本相同:

如果类型
template<typename T> struct is_array
{ static const bool value = false; };

template<typename T> struct is_array<T[]>
{ static const bool value = true; };

template<typename T, size_t n> struct is_array<T[n]>
{ static const bool value = true; };
template<typename T> struct is_reference
{ static const bool value = false; };

template<typename T> struct is_reference<T&>
{ static const bool value = true; };

template<typename T> struct is_void
{ static const bool value = false; };

template<> struct is_void<void>
{ static const bool value = true; };

template<> struct is_void<void const>
{ static const bool value = true; };

template<> struct is_void<void volatile>
{ static const bool value = true; };

template<> struct is_void<void const volatile>
{ static const bool value = true; };
template<typename T>
class is_abstract_class_or_function
{
    typedef char (&Two)[2];
    template<typename U> static char test(U(*)[1]);
    template<typename U> static Two test(...);

public:
    static const bool value =
        !is_reference<T>::value &&
        !is_void<T>::value &&
        (sizeof(test<T>(0)) == sizeof(Two));
};
template<typename T>
class is_class
{
    typedef char (&Two)[2];
    template<typename U> static char test(int (U::*));
    template<typename U> static Two test(...);

public:
    static const bool value = (sizeof(test<T>(0)) == sizeof(char));
};
template<typename T> struct is_returnable
{ static const bool value = !is_array<T>::value && !is_abstract_class_or_function<T>::value; };
#include <limits>
#include <type_traits>

struct Incomplete;
struct Abstract { virtual void f() = 0; };

template<typename T>
  using is_numeric_limits_safe = std::is_convertible<T, T>;

int main()
{
  static_assert(!is_numeric_limits_safe<Incomplete>::value, "Incomplete");
  static_assert(!is_numeric_limits_safe<Abstract>::value,   "Abstract");
  static_assert(!is_numeric_limits_safe<int[2]>::value,     "int[2]");
}
template<typename T>
class is_numeric_limits_unsafe
{
  struct mu { };

  template<typename U>
    static U test(int);

  template<typename U>
    static mu test(...);

public:
    typedef std::is_same<decltype(test<T>(0)), mu> type;
};

template<typename T>
struct is_numeric_limits_safe
: std::integral_constant<bool, !is_numeric_limits_unsafe<T>::type::value>
{ };