【问题标题】:Is there a "dynamic decltype"?是否有“动态 decltype”?
【发布时间】:2014-10-19 21:05:55
【问题描述】:

这个问题与decltype和多重继承有关。

假设我有以下内容:

  • 一个带有一些虚方法的抽象类 A,
  • 一些派生类使用以前的虚拟方法实现方法(这些类中的每一个都是一种用例),
  • 最终的具体类,继承自先前用例的子集并实现纯虚方法。

例如:

#include <iostream>

/**
 * "Iterable container"
 */
template <class T>
struct A
{
    virtual T* data() =0;
    virtual const T* data() const =0;
    virtual unsigned size() const =0;

    T* begin() { return data(); }
    T* end() { return data()+size(); }

    const T* begin() const { return data(); }
    const T* end() const { return data()+size(); }
};

// ------------------------------------------------------------------------

/**
 * Iterative assignment
 */
template <class T>
struct B: public A<T>
{
    auto operator =( const T& val ) -> decltype(*this)
    {
        for ( auto& v: *this ) v = val;
        return *this;
    }
};

/**
 * Iterative display
 */
template <class T>
struct C: public A<T>
{
    void show() const
    {
        for ( auto& v: *this )
            std::cout<< v << " ";
            std::cout<< std::endl;
    }
};

// ------------------------------------------------------------------------

/**
 * Concrete implementation
 */
template <class T, unsigned N>
struct D:
    public B<T>, 
    public C<T>
{
    using B<T>::operator=;

    T dat[N];

    T* data() { return dat; }
    const T* data() const { return dat; }
    unsigned size() const { return N; }
};

// ------------------------------------------------------------------------

int main()
{
    D<double,5> d;
    (d = 42).show(); // compile-time error, "no member named 'show' in 'B<double>'"
}

问题是这个(不是双关语);如果“用例”方法之一应该返回对*this 的引用,我希望this 成为对最终具体类的引用,以便我可以将调用与来自其他用例的其他方法链接起来.

但是,使用以前的实现,我得到一个编译时错误。还有其他方法可以实现我所解释的吗?

【问题讨论】:

    标签: c++ c++11 multiple-inheritance decltype


    【解决方案1】:

    解决方法是使用CRTP;您告诉B 通过将派生最多的类型作为附加模板参数传递来返回对D&lt;T, N&gt; 的左值引用。

    template <class T, class Derived>
    struct B: public A<T>
    {
        auto operator =( const T& val ) -> Derived&
        // ...
    
    template <class T, unsigned N>
    struct D:
        public B<T, D<T, N>>,
        // ...
    

    【讨论】:

    • 非常有趣!当我们在继承列表中写入D&lt;T,N&gt; 时,这不会造成“循环定义”类型的问题吗?
    • 它没有,因为成员函数声明中的返回类型允许是不完整的类类型。当您实例化成员函数体时,D&lt;T, N&gt; 已完成,因此一切正常。
    【解决方案2】:

    您可以给 D 一个覆盖 operator= 以返回 D &amp;

    auto operator =( const T& val ) -> decltype(*this) override
    {
        B<T>::operator=(val);
        return *this;
    }
    

    这是因为D &amp;B &amp; 是协变的,并且覆盖函数必须具有协变的返回类型。这目前也影响了Boperator=,因为那个不是virtual

    【讨论】:

    • decltype(auto) 怎么样?
    • 谢谢,我现在明白了 :) 这是一个很好的解决方案,但它本质上需要重新实现每个返回 *this 的方法,这对我来说似乎并不理想。
    • @Nawaz,这个问题被标记为 C++11,所以我想这就是正在使用的。
    • @Sh3ljohn,没错,尽管至少你可以重用基础的实现,但我不得不质疑拥有这么多这样的功能,这会成为一个问题。
    • 请注意,您可以将此实现与@ecatmur 的实现混合使用:拥有一个纯虚拟基础、一个CRTP 助手和一个最终实现。 CRTP 助手使用正确类型的返回值扩展了纯虚拟方法。这仅在您打算传递指向纯虚拟基的指针时才有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-17
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    • 2021-08-20
    • 1970-01-01
    相关资源
    最近更新 更多