【问题标题】:C++: Explicitly call destructor of template parameter's typedefC ++:显式调用模板参数的typedef的析构函数
【发布时间】:2018-02-03 01:32:43
【问题描述】:

我有以下几点:

template <typename X> struct A {
    typedef X _X;
};

template <typename Y> struct B { // Y is struct A
    typename Y::_X x;
    void call_destructor () {
        x.~Y::_X(); // This doesn't work
        x.Y::~_X(); // This as well
    }
}; 

哪个不编译,这么说

限定类型与析构函数名称不匹配

在调用之前使用关键字typename 也不起作用。但是,以下内容可以编译:

template <typename Y> struct B {
    typename Y::_X x;
    typedef typename Y::_X __X;
    void call_destructor () {
        x.~__X(); // This works
    }
};

有人可以向我解释原因吗?没有typedef 有什么办法吗?

【问题讨论】:

    标签: c++ destructor typedef


    【解决方案1】:

    你应该使用不同的方式调用析构函数

    x.Y::_X::~_X()
    

    以下编译对我来说很好:

    template <typename X> struct A {
        typedef X _X;
    };
    
    template <typename Y> struct B { // Y is struct A
        typename Y::_X x;
        void call_destructor () {
           x.Y::_X::~_X(); // This as well
        }
    }; 
    
    
    int main(){
      B<A<int> > b;
      b.call_destructor();
    }
    

    【讨论】:

    • 有趣的是,这在 Clang 上不起作用。我想知道这是否是一个错误,或者是否有一些模糊的规则导致它的格式不正确。
    • 确实,我一开始只用gcc试过。这对我来说是个谜。
    【解决方案2】:
    x.~Y::_X(); // This doesn't work
    

    是语法错误,相信编译器会解析为在~Y中调用_X

    在第二种情况下,当你调用包含::的析构函数时,最后两个类型名称必须表示相同的类型

    s.A::~B();
    

    其中AB 必须是同一类型。 AB 都在先前说明符指定的范围内查找,如果有的话

    x._X::~_X();     // error, can't find _X in current scope
    

    合乎逻辑的解决办法是

    x.Y::_X::~_X();           // error, _X is dependent name
    x.typename Y::_X::~_X();  // error, typename cannot be here
    

    由于Y::_Xdependent name,需要typename 来消除它作为类型的歧义,但析构函数的语法不允许在表达式中使用typename。最终结果是您必须使用类型别名

    using X = typename Y::_X;
    x.~X();
    

    另一方面,写后忘记析构函数调用最简单的方法就是

    x.~decltype(x)();
    

    但是 gcc 和 msvc 编译失败。

    †​​ 更准确地说,是伪析构函数调用

    【讨论】:

    • 不应该[temp.res]/4申请吗?
    • @xskxzr 语法产生规则要求nested-name-specifier 正好是type-name ::,这就排除了这一点。或者我认为。
    【解决方案3】:

    使用此方法https://stackoverflow.com/a/17328828/15006896,我能够为分配的数组中的每个对象调用析构函数,该数组包含模板函数中未指定的依赖类型。

    即:

    template <typename CompoundType>
    void process_data()
    {
        const size_t MAX_SIZE = some_value;
        CompoundType* obj_list = new CompoundType[MAX_SIZE];
    
        // Receive data into obj_list and process it...
    
        CompoundType* p_record = records;
        for (int i = 0; i < MAX_SIZE; i++)
        {
            // Below is the magic to call the destructors!
            p_record->std::remove_reference<decltype(*p_record)>::type::~type();
            p_record++;
        }
    
        delete[] obj_list;
    }
    

    注意:上面的模板函数是用以下特化调用的,每个内部类都动态分配内存:

    process_data<A::One>();
    process_data<B::Two>();
    process_data<C::Three>();
    

    即:模板函数内部不知道内部类的名称,简单地尝试调用~CompoundType根本不起作用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-04
      相关资源
      最近更新 更多