【问题标题】:How does template specialization with integer types work?整数类型的模板特化如何工作?
【发布时间】:2018-02-15 19:27:41
【问题描述】:

我有一个带有单个参数<T> 的模板函数,我想针对不同的整数类型对这个函数进行专门化处理。起初这似乎很明显,但经过几次尝试后,我发现我并不真正了解专业化在这里的真正运作方式,以及如何实现某种程度的可移植性......

这是测试程序:

// clang test.cc -std=c++11 -lc++
#include <iostream>
#include <typeinfo>

template <typename T> void foo()  { std::cout << "  foo<T> with T=" << typeid(T).name() << '\n'; }
template <> void foo<int>()       { std::cout << "  foo<int>\n"; }
template <> void foo<long>()      { std::cout << "  foo<long>\n"; }
template <> void foo<long long>() { std::cout << "  foo<long long>\n"; }
template <> void foo<size_t>()    { std::cout << "  foo<size_t>\n"; }
// template <> void foo<int64_t>()  { std::cout << "  foo<int64_t>\n"; } // error


int main () {
  std::cout << "sizeof(int)=" << sizeof(int) << ", ";
  std::cout << "sizeof(long)=" << sizeof(long) << ", ";
  std::cout << "sizeof(long long)=" << sizeof(long long) << ", ";
  std::cout << "sizeof(size_t)=" << sizeof(size_t) << "\n";
  foo<int>();
  foo<long>();
  foo<long long>();
  foo<size_t>();
  foo<ssize_t>();
  foo<int8_t>();
  foo<int16_t>();
  foo<int32_t>();
  foo<int64_t>();
  foo<uint32_t>();
  foo<uint64_t>();
  return 0;
}

它在我的机器上产生

sizeof(int)=4, sizeof(long)=8, sizeof(long long)=8, sizeof(size_t)=8
  foo<int>
  foo<long>
  foo<long long>
  foo<size_t>
  foo<long>
  foo<T> with T=a
  foo<T> with T=s
  foo<int>
  foo<long long>
  foo<T> with T=j
  foo<T> with T=y

这就是我不明白的地方:

  1. 如果longlong long 是同一类型,为什么编译器允许这两种特化共存?
  2. 为什么为 int64_t 添加专业化会产生错误?
  3. 为什么foo&lt;int64_t&gt; 解析为foo&lt;long long&gt; 而不是foo&lt;long&gt;
  4. 为什么foo&lt;ssize_t&gt; 解析为foo&lt;long&gt; 而不是foo&lt;long long&gt;
  5. 为什么foo&lt;uint64_t&gt; 不使用特化@9​​87654334@?
  6. 我在这里观察到的行为是通用的还是特定于机器的?如何确定此代码是可移植的?

【问题讨论】:

  • int64_tssize_t 等类型只是longunsigned long 等内置类型的别名。与其他一些语言不同,C++ 不提供任何声明“强”类型别名的方法,因此针对同一底层类型的不同别名的模板特化总是会导致错误。
  • #1 是您的错误假设。 “相同大小”并不意味着“相同类型”。就像 charsigned charunsigned char 的不同类型一样,尽管它的行为与其中一个相同。
  • 'long' 和 'long long' 与您的编译器的 size 相同,但它们的 type 不同。
  • @Pete Becker 并且,取决于平台/编译器,可能不会总是是相同的大小。

标签: c++ c++11 templates template-specialization


【解决方案1】:

1) 如果longlong long 是同一类型,为什么编译器允许这两种特化共存?

因为longlong long 可以在相同的低级类型上实现,但从语言的角度来看,它们是不同的基本类型。

2) 为什么为 int64_t 添加特化会产生错误?

因为std::int64_t 不是算术基本类型,而是另一种类型的别名(通过typedefusing 定义)

3) 为什么foo&lt;int64_t&gt; 解析为foo&lt;long long&gt; 而不是foo&lt;long&gt;

因为,在您的平台中,std::int64_t 被定义为long long 的别名,而不是long(或别名的别名...);所以,在你的平台上,std::int64_tlong long;在不同的平台上,你可以得到不同的结果

4) 为什么foo&lt;ssize_t&gt; 解析为foo&lt;long&gt; 而不是foo&lt;long long&gt;

std::int64_t 相同:ssize_t 类型(不是标准类型)是long 的别名(在您的平台中),而不是long long 的别名

5) 为什么foo&lt;uint64_t&gt; 不使用特化@9​​87654345@?

因为std::uint64_tstd::size_t 不是基本算术类型,但它们都是其他类型的别名(我想是unsigned longunsigned long long),并且在您的平台中,它们是不同类型的别名

6) 我在这里观察到的行为是普遍的,还是特定于机器的?我如何确定这段代码是可移植的?

除了第 (1) 点之外(这是正确的,因为 longlong long 之间的区别是语言的一部分),很大程度上依赖于平台。

但可以使用std::is_same 和其他类型特征来管理它。

【讨论】:

    【解决方案2】:

    c++ 中,尽管相同,但两种类型可能不同。例如,charunsigned charsigned char 相同,但仍然是不同的类型。在您的情况下,longlong long 相同但不同。这类似于 struct A{};struct B{}; 是相同但不同的类型。

    另外要了解的是typedefusing 不能创建新类型。

    1. 如果longlong long 是同一类型,为什么编译器允许这两种特化共存?

    longlong long 类型是不同的类型,即使它们的大小相同。

    1. 为什么为 int64_t 添加专业化会产生错误?

    对于其他内置类型,固定宽度整数类型为typedefs。在您的情况下,int64_tlong intlong long int 的类型定义。您已经为它作为别名的任何类型提供了一个specialize。与前一种情况不同,int64_t 没有命名不同的类型。

    1. 为什么foo&lt;int64_t&gt; 解析为foo&lt;long long&gt; 而不是foo&lt;long&gt;
    2. 为什么foo&lt;ssize_t&gt; 解析为foo&lt;long&gt; 而不是foo&lt;long long&gt;

    它可能会解决一个或另一个。这取决于源代码编译的平​​台。

    1. 为什么foo&lt;uint64_t&gt; 不使用特化@9​​87654350@?

    同样,uint64_tsize_t 别名的类型取决于平台。在这种情况下,它们似乎只是为不同的类型加上别名。

    1. 我在这里观察到的行为是通用的还是特定于机器的?如何确定此代码是可移植的?

    您观察到的大多数行为都取决于平台。虽然可移植性并不意味着在所有平台上的行为都是相同的,只是它会在所有平台上做正确的事情。如果您的意图是显示int 的大小,那么在具有不同大小int 的平台上行为会有所不同是正常的。最终,这里的可移植性错误是假设相同的类型是相同的类型。

    如果您的代码取决于这些类型的具体细节,您可以使用std::numeric_limits&lt;type_traits&gt; 标头,而不是假设您使用的类型。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多