【问题标题】:Cast a template object with different template parameters, how is this possible?用不同的模板参数强制转换模板对象,这怎么可能?
【发布时间】:2015-06-21 19:43:01
【问题描述】:

今天我尝试了一些东西,认为它不起作用,但它确实有效,我不明白为什么......

我有一个 base 类型的对象,它什么都不包含。
另一个derived类型,继承自base,存储一个函数指针并调用它。
derived是一个模板对象,它的参数是存储的函数等待的参数的类型。

如果我从derived<void> 类型的对象中引用base 类型并尝试将其转换为derived<int>... 它确实有效。
derived<>derived< int >是两种不同的类型,你怎么解释?

一个简单的例子:

#include <iostream>

void foo( int ) { ::std::cout << "void foo( int )\n"; }
void foo() { ::std::cout << "void foo()\n"; }

struct base
{
  base() { ::std::cout << "\tcreate base\n"; }
  base( const base & ) { ::std::cout << "\tcopy base\n"; }
  base( base && ) { ::std::cout << "\tmove base\n"; }

  void operator =( const base & ) { ::std::cout << "\tcopy assignment base\n"; }
  void operator =( base && ) { ::std::cout << "\tmove assignment base\n"; }
};

template < typename ... Args >
struct derived : public base
{
  derived() { ::std::cout << "\tcreate derived\n"; }
  derived( const derived & ) { ::std::cout << "\tcopy derived\n"; }
  derived( derived && ) { ::std::cout << "\tmove derived\n"; }

    derived & operator =( const derived & ) { ::std::cout << "\tcopy assignment derived\n"; }
  derived & operator =( derived && ) { ::std::cout << "\tmove assignment derived\n"; }

  void operator ()( Args ... args )
  {
    f( args ... );
  }

  void ( *f )( Args ... );
};


int main()
{
  derived<> derived_void;
  derived_void.f = ( void ( * )() )&foo;

  base & base_void = derived_void;
  derived<> &test = derived_void;

  static_cast< derived< int > & >( base_void )( 1 ); // compiles, makes no copy
//  static_cast< derived< int > & >( test )( 1 ); // doesn't compile
}

You can test it here.

感谢您的帮助。

【问题讨论】:

    标签: c++ templates inheritance casting


    【解决方案1】:

    忘记模板。

    您有一个类A、一个派生自A 的类B,以及一个派生自A 的类C

    如果您有一个A 类型的左值,您可以将其转换为B &amp;C &amp;。编译器通常无法知道具体派生类型是什么,因此它相信您知道自己在做什么。

    这正是您正在做的事情:您将A 转换为B &amp;。您的 A 确实是 C 对象,但编译器不知道。

    【讨论】:

    • 在我看来,OP 可能希望(期望?)检查动态类型。也许解释一下他如何使用dynamic_cast会有用?
    • @bogdan 这对于问题中的类型是不可能的:没有一个类是多态的。
    • 完全正确,因此“解释如何他可以使用”。这只是添加一个虚拟析构函数定义的问题,无论如何这可能是个好建议,因为他通过引用访问这些对象,这种方式通常与运行时多态性相关联。
    【解决方案2】:

    考虑一下:

    struct X {};
    struct A : X {};
    struct B : X {};
    
    X & x = get_object_ref(); //can return A& or B&, how would I know?
    
    A & a = static_cast<A&>(x); //this will compile!
    B & b = static_cast<B&>(x); //this will compile too!
    

    如果static_cast&lt;A&amp;&gt;(x) 应该给出错误,那么static_cast&lt;B&amp;&gt;(x) 也应该通过对称给出错误。既然要编译,那两个都要编译。

    底线:base&amp; 总是可以向下转换为 derive&amp; — 这是一种语言特性。您有责任投到正确 derive&amp;

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-03-26
      • 1970-01-01
      • 1970-01-01
      • 2011-10-01
      • 1970-01-01
      • 2015-05-13
      • 1970-01-01
      相关资源
      最近更新 更多