14

我有一个结构模板,它采用两种类型(TS),并且在某些时候使用 astatic_cast从一种类型转换为另一种类型。通常情况下TS是同一类型。

设置的简化示例:

template <typename T, typename S = T>
struct foo
{
  void bar(T val)
  {
    /* ... */
    some_other_function(static_cast<S>(val));
    /* ... */
  }
};

在与S相同的类的情况下T,是否或可以static_cast引入额外的开销,或者它是一个始终被忽略的空操作?

如果它确实引入了开销,是否有一个简单的模板元编程技巧来static_cast仅在需要时执行,还是我需要创建一个部分专业化来应对这种T == S情况?如果可能的话,我宁愿避免整个foo模板的部分专业化。

4

2 回答 2

12

是的,它可以。

这是一个例子:

struct A {
  A( A const& ) {
    std::cout << "expensive copy\n";
  }
};

template<typename T>
void noop( T const& ) {}
template <typename T, typename S = T>
void bar(T val)
{
  noop(static_cast<S>(val));
}
template <typename T>
void bar2(T val)
{
  noop(val);
}
int main() {
  std::cout << "start\n";
  A a;
  std::cout << "bar2\n";
  bar2(a); // one expensive copy
  std::cout << "bar\n";
  bar(a); // two expensive copies
  std::cout << "done";
}

基本上, astatic_cast可以诱导调用复制构造函数。

对于某些类型(如int),复制构造函数基本上是免费的,编译器可以消除它。

对于其他类型,它不能。在这种情况下,复制省略也是不合法的:如果您的复制构造函数有副作用或者编译器无法证明它没有副作用(如果复制构造函数不平凡,则很常见),它将被调用。

于 2013-10-01T02:54:22.243 回答
5

为了补充Yakk 的回答,我决定发布一些程序集来确认这一点。我已经用作std::string测试类型。

foo<std::string>.bar()- 没有铸造

pushq   %rbp
movq    %rsp, %rbp
subq    $32, %rsp
movq    %rcx, 16(%rbp)
movq    %rdx, 24(%rbp)
movq    24(%rbp), %rax
movq    %rax, %rcx
call    _Z19some_other_functionRKSs
nop
addq    $32, %rsp
popq    %rbp
ret

foo<std::string>.bar()-static_cast<T>()

pushq   %rbp
pushq   %rbx
subq    $56, %rsp
leaq    128(%rsp), %rbp
movq    %rcx, -48(%rbp)
movq    %rdx, -40(%rbp)
movq    -40(%rbp), %rdx
leaq    -96(%rbp), %rax
movq    %rax, %rcx
call    _ZNSsC1ERKSs     // std::string.string()
leaq    -96(%rbp), %rax
movq    %rax, %rcx
call    _Z19some_other_functionRKSs
leaq    -96(%rbp), %rax
movq    %rax, %rcx
call    _ZNSsD1Ev    // std::string.~string()
jmp .L12
movq    %rax, %rbx
leaq    -96(%rbp), %rax
movq    %rax, %rcx
call    _ZNSsD1Ev    // std::string.~string()
movq    %rbx, %rax
movq    %rax, %rcx
call    _Unwind_Resume
nop
.L12:
addq    $56, %rsp
popq    %rbx
popq    %rbp
ret


此代码仅使用生成-O0。任何优化级别都会平衡这两种情况。

于 2013-10-01T03:10:55.967 回答