【问题标题】:Implementing a function of a templated interface with pointer as return type -> Conflicting return type error使用指针作为返回类型实现模板化接口的功能->冲突返回类型错误
【发布时间】:2021-10-23 03:39:19
【问题描述】:

我目前正在学习 C++,并且遇到了以下问题:我有一个模板化接口 BaseTemplate,我想在子类中实现它而不使子类本身成为模板。示例代码如下:

template <typename T>
class BaseTemplate
{
    public:
        virtual const T get() const = 0;
};

class Child : public BaseTemplate<int*>
{
    public:
        Child(int value) : myInt{value} {};
        virtual const int* get() const override { return &myInt; };

    private:
        int myInt{0};
};

int main()
{
    Child myChild = Child(10);
    std::cout << myChild.get() << "\n";
    return 0;
}

GCC 产生以下错误:

main.cpp|16|error: conflicting return type specified for ‘virtual const int* Child::get() const’
main.cpp|9|note: overridden function is ‘const T BaseTemplate<T>::get() const [with T = int*]’

我清楚地了解该错误与 virtual const int* get() const override { return &amp;myInt; }; 但我不明白有什么问题。如果我将返回类型(当然在两个类中)更改为int,我。 e.返回一个值而不是指针,它工作正常。那么这里的指针有什么问题呢?

也许它有帮助:在我的实际代码中,我想返回一个指向自定义接口而不是 int 的指针,我相信那里的错误是相关的

file_trees.h|19|error: invalid covariant return type for ‘virtual const IDirectoryNode* FileTree::DepthFirstIterator::getCurrent() const’
iterator_interface.h|10|note: overridden function is ‘const T IIterator<T>::getCurrent() const [with T = IDirectoryNode*]’

【问题讨论】:

    标签: c++ templates inheritance gcc return-type


    【解决方案1】:

    这必须归功于const 如何应用于类型。

    const T 表示返回值是常量(当然几乎没用)。对于指针,这意味着指针本身是常量,而不是它的目标。

    另一方面,const int* 是指向 const int 值的非常量指针。

    对于Base&lt;int*&gt;T=int* 产生int* const,而不是const* int,所以你必须定义int* const get() 虚方法。

    对于T=const int*,它将是const int* const。详情请见this question

    【讨论】:

    • 我看到了问题。因此,如果我的意图是有一个指向常量值的指针(即保护值不被指针更改),最简单的方法是使我的抽象定义 virtual T get() const = 0; 并使用 const int* 作为我的模板类型名,即。 e. Child : public BaseTemplate&lt;const int*&gt;virtual const int* get() const override {...}。正确的?这对我来说看起来也更优雅。
    【解决方案2】:

    当你有一个

    int *
    

    这种类型的常量版本不是const int *。它是int * const,或指向int 的常量指针。 const int * 是指向常量int 的指针,这是一个完全不同的类型。

    但是,修复返回类型是不够的,因为get()const 类方法。将指针指向它的数据指针会生成 const int *,而不是 int *

    这里最简单的解决办法可能是让这个类成员可变:

    class Child : public BaseTemplate<int*>
    {
        public:
            Child(int value) : myInt{value} {};
            virtual int *const get() const override { return &myInt; };
    
        private:
            mutable int myInt{0};
    };
    
    

    无需从根本上重新设计整个类层次结构,这是使其编译的最小修复。您应该完全理解成为班级成员mutable 的含义,并理解所有含义。

    【讨论】:

    • 我觉得我的意图不是很清楚。我不想要一个常量指针,我想保护值不被指针改变。所以我猜const int *已经是正确的选择了,只是我现在对const、指针和模板的理解还不够。
    • 好吧,如果模板参数Tint *,那么其中的const 就是int *const。这就是 C++ 的工作原理。您可能必须声明一个特化,以便当T 是一个指针时,get() 不会返回const T,而是constT 指向的类型。在任何情况下,const 返回值并不真正意味着您认为它是什么。这意味着接收到返回值的人不能修改它,而不是接收到这个返回值的人不能修改该值指向的任何内容,如果它是一个指针。
    【解决方案3】:

    int*const 版本是int* const,它是一个指向整数类型的常量指针,而不是指向const int 的指针。

    您的意图可以通过以下方式实现。

    template<class T>
    struct const_type_handler
    {
        using type=const T;
    };
    
    template<class T>
    struct const_type_handler<T*>
    {
        using type=const T*;
    };
    
    
    template <typename T>
    class BaseTemplate
    {
        public:
            virtual typename const_type_handler<T>::type get() const = 0;
    };
    
    class Child : public BaseTemplate<int*>
    {
        public:
            Child(int value) : myInt{value} {};
            virtual typename const_type_handler<int*>::type get() const override { return &myInt; };
    
        private:
            int myInt{0};
    };
    

    我知道这会让代码有点乱,但它确实有效!

    【讨论】:

    • 可以用type_traits:using underlying_type = std::conditional_t&lt;std::is_pointer_t&lt;T&gt;, const std::remove_pointer_t&lt;T&gt;*, const T&gt;;稍微缩短一点。如果它是一个指针(可能是有意的),这将丢失T 的 cv 限定符。
    • 绝对是一个有趣的想法。但我想我现在会坚持一种更简单的方法。还是谢谢!
    猜你喜欢
    • 2013-02-03
    • 2020-07-27
    • 1970-01-01
    • 1970-01-01
    • 2018-09-05
    • 1970-01-01
    • 1970-01-01
    • 2013-07-22
    • 2011-05-16
    相关资源
    最近更新 更多